summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--ApiDocs.bp8
-rw-r--r--PREUPLOAD.cfg1
-rw-r--r--StubLibraries.bp33
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java13
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java16
-rw-r--r--api/Android.bp90
-rw-r--r--api/current.txt27
-rw-r--r--api/module-lib-current.txt1
-rw-r--r--api/system-current.txt6
-rw-r--r--api/test-current.txt5
-rw-r--r--cmds/bootanimation/BootAnimation.cpp110
-rw-r--r--cmds/bootanimation/BootAnimation.h12
-rw-r--r--cmds/bootanimation/FORMAT.md8
-rw-r--r--cmds/statsd/src/condition/ConditionTimer.h48
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp115
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h20
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp106
-rw-r--r--cmds/statsd/src/metrics/parsing_utils/config_update_utils.h16
-rw-r--r--cmds/statsd/tests/condition/ConditionTimer_test.cpp6
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp2053
-rw-r--r--cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp78
-rw-r--r--core/java/android/app/ActivityManagerInternal.java27
-rw-r--r--core/java/android/app/AppOpsManager.java84
-rw-r--r--core/java/android/app/PendingIntent.java52
-rw-r--r--core/java/android/bluetooth/BluetoothCodecConfig.java32
-rw-r--r--core/java/android/bluetooth/BluetoothCodecStatus.java5
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/content/pm/PackageInstaller.java1
-rw-r--r--core/java/android/hardware/display/DisplayManager.java1
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java9
-rw-r--r--core/java/android/permission/PermissionManager.java15
-rw-r--r--core/java/android/provider/Settings.java22
-rw-r--r--core/java/android/util/IntArray.java11
-rw-r--r--core/java/android/view/SurfaceControl.java43
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java70
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java272
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java15
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java19
-rw-r--r--core/java/com/android/internal/os/BinderInternal.java8
-rw-r--r--core/java/com/android/internal/os/SystemServerCpuThreadReader.java18
-rw-r--r--core/java/com/android/internal/protolog/ProtoLogGroup.java4
-rw-r--r--core/proto/android/providers/settings/secure.proto10
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--core/tests/coretests/AndroidManifest.xml9
-rw-r--r--core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java130
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java38
-rw-r--r--core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java99
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java10
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java27
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java4
-rw-r--r--core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java15
-rw-r--r--data/etc/platform.xml7
-rw-r--r--data/etc/services.core.protolog.json45
-rw-r--r--graphics/java/android/graphics/BlurShader.java28
-rw-r--r--graphics/java/android/graphics/ParcelableColorSpace.java2
-rw-r--r--graphics/java/android/graphics/Shader.java6
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java31
-rw-r--r--libs/hwui/SkiaCanvas.cpp3
-rw-r--r--libs/hwui/SkiaCanvas.h3
-rw-r--r--libs/hwui/hwui/Canvas.cpp18
-rw-r--r--libs/hwui/hwui/Canvas.h3
-rw-r--r--libs/hwui/jni/Shader.cpp5
-rw-r--r--libs/hwui/shader/BlurShader.cpp5
-rw-r--r--libs/hwui/shader/BlurShader.h6
-rw-r--r--media/Android.bp93
-rw-r--r--media/OWNERS4
-rw-r--r--media/aidl/android/media/audio/common/AudioChannelMask.aidl (renamed from media/java/android/media/audio/common/AudioChannelMask.aidl)0
-rw-r--r--media/aidl/android/media/audio/common/AudioConfig.aidl (renamed from media/java/android/media/audio/common/AudioConfig.aidl)0
-rw-r--r--media/aidl/android/media/audio/common/AudioFormat.aidl (renamed from media/java/android/media/audio/common/AudioFormat.aidl)0
-rw-r--r--media/aidl/android/media/audio/common/AudioOffloadInfo.aidl (renamed from media/java/android/media/audio/common/AudioOffloadInfo.aidl)0
-rw-r--r--media/aidl/android/media/audio/common/AudioStreamType.aidl (renamed from media/java/android/media/audio/common/AudioStreamType.aidl)0
-rw-r--r--media/aidl/android/media/audio/common/AudioUsage.aidl (renamed from media/java/android/media/audio/common/AudioUsage.aidl)0
-rw-r--r--media/aidl/android/media/permission/Identity.aidl (renamed from media/java/android/media/permission/Identity.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl (renamed from media/java/android/media/soundtrigger_middleware/AudioCapabilities.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl (renamed from media/java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl (renamed from media/java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl (renamed from media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl (renamed from media/java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl (renamed from media/java/android/media/soundtrigger_middleware/ModelParameter.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl (renamed from media/java/android/media/soundtrigger_middleware/ModelParameterRange.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/OWNERS (renamed from media/java/android/media/soundtrigger_middleware/OWNERS)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/Phrase.aidl (renamed from media/java/android/media/soundtrigger_middleware/Phrase.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl (renamed from media/java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl (renamed from media/java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl (renamed from media/java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl (renamed from media/java/android/media/soundtrigger_middleware/RecognitionConfig.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl (renamed from media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl (renamed from media/java/android/media/soundtrigger_middleware/RecognitionMode.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl (renamed from media/java/android/media/soundtrigger_middleware/RecognitionStatus.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl (renamed from media/java/android/media/soundtrigger_middleware/SoundModel.aidl)3
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl (renamed from media/java/android/media/soundtrigger_middleware/SoundModelType.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl (renamed from media/java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl (renamed from media/java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl)0
-rw-r--r--media/aidl/android/media/soundtrigger_middleware/Status.aidl (renamed from media/java/android/media/soundtrigger_middleware/Status.aidl)0
-rw-r--r--media/java/android/media/AudioAttributes.aidl2
-rw-r--r--media/java/android/media/AudioManager.java22
-rw-r--r--media/java/android/media/ExifInterface.java26
-rw-r--r--media/java/android/media/MediaMetadata.aidl2
-rw-r--r--media/java/android/media/MediaTranscodeManager.java122
-rw-r--r--media/java/android/media/RemoteController.java2
-rw-r--r--media/java/android/media/session/MediaSessionManager.java55
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java44
-rw-r--r--non-updatable-api/Android.bp35
-rw-r--r--non-updatable-api/current.txt21
-rw-r--r--non-updatable-api/module-lib-current.txt1
-rw-r--r--non-updatable-api/system-current.txt4
-rw-r--r--packages/CarSystemUI/res/layout/sysui_overlay_window.xml3
-rw-r--r--packages/CarSystemUI/res/values/dimens.xml6
-rw-r--r--packages/CarSystemUI/res/values/strings.xml2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java23
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java25
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java42
-rw-r--r--packages/InputDevices/res/values-af/strings.xml3
-rw-r--r--packages/InputDevices/res/values-am/strings.xml3
-rw-r--r--packages/InputDevices/res/values-as/strings.xml3
-rw-r--r--packages/InputDevices/res/values-az/strings.xml3
-rw-r--r--packages/InputDevices/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/InputDevices/res/values-be/strings.xml3
-rw-r--r--packages/InputDevices/res/values-bg/strings.xml3
-rw-r--r--packages/InputDevices/res/values-bs/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ca/strings.xml3
-rw-r--r--packages/InputDevices/res/values-da/strings.xml3
-rw-r--r--packages/InputDevices/res/values-de/strings.xml3
-rw-r--r--packages/InputDevices/res/values-el/strings.xml3
-rw-r--r--packages/InputDevices/res/values-es-rUS/strings.xml3
-rw-r--r--packages/InputDevices/res/values-es/strings.xml3
-rw-r--r--packages/InputDevices/res/values-et/strings.xml3
-rw-r--r--packages/InputDevices/res/values-eu/strings.xml3
-rw-r--r--packages/InputDevices/res/values-fa/strings.xml3
-rw-r--r--packages/InputDevices/res/values-fi/strings.xml3
-rw-r--r--packages/InputDevices/res/values-gl/strings.xml3
-rw-r--r--packages/InputDevices/res/values-gu/strings.xml3
-rw-r--r--packages/InputDevices/res/values-hr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-hu/strings.xml3
-rw-r--r--packages/InputDevices/res/values-hy/strings.xml3
-rw-r--r--packages/InputDevices/res/values-in/strings.xml3
-rw-r--r--packages/InputDevices/res/values-is/strings.xml3
-rw-r--r--packages/InputDevices/res/values-it/strings.xml3
-rw-r--r--packages/InputDevices/res/values-iw/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ja/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ka/strings.xml3
-rw-r--r--packages/InputDevices/res/values-kn/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ko/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ky/strings.xml3
-rw-r--r--packages/InputDevices/res/values-lo/strings.xml3
-rw-r--r--packages/InputDevices/res/values-lt/strings.xml3
-rw-r--r--packages/InputDevices/res/values-lv/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ml/strings.xml3
-rw-r--r--packages/InputDevices/res/values-mn/strings.xml3
-rw-r--r--packages/InputDevices/res/values-mr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ms/strings.xml3
-rw-r--r--packages/InputDevices/res/values-my/strings.xml3
-rw-r--r--packages/InputDevices/res/values-nb/strings.xml3
-rw-r--r--packages/InputDevices/res/values-nl/strings.xml3
-rw-r--r--packages/InputDevices/res/values-or/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pa/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pl/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/InputDevices/res/values-pt/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ro/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ru/strings.xml3
-rw-r--r--packages/InputDevices/res/values-si/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sk/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sl/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sv/strings.xml3
-rw-r--r--packages/InputDevices/res/values-sw/strings.xml3
-rw-r--r--packages/InputDevices/res/values-te/strings.xml3
-rw-r--r--packages/InputDevices/res/values-th/strings.xml3
-rw-r--r--packages/InputDevices/res/values-tr/strings.xml3
-rw-r--r--packages/InputDevices/res/values-uk/strings.xml3
-rw-r--r--packages/InputDevices/res/values-ur/strings.xml3
-rw-r--r--packages/InputDevices/res/values-uz/strings.xml3
-rw-r--r--packages/InputDevices/res/values-vi/strings.xml3
-rw-r--r--packages/InputDevices/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/InputDevices/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/InputDevices/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/InputDevices/res/values-zu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hy/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java9
-rw-r--r--packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java22
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/layout/media_output_dialog.xml24
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml2
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml5
-rw-r--r--packages/SystemUI/res/layout/partial_conversation_info.xml5
-rw-r--r--packages/SystemUI/res/layout/window_magnifier_view.xml9
-rw-r--r--packages/SystemUI/res/values-af/strings.xml21
-rw-r--r--packages/SystemUI/res/values-am/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml21
-rw-r--r--packages/SystemUI/res/values-as/strings.xml21
-rw-r--r--packages/SystemUI/res/values-az/strings.xml21
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml21
-rw-r--r--packages/SystemUI/res/values-be/strings.xml21
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml21
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml27
-rw-r--r--packages/SystemUI/res/values-da/strings.xml21
-rw-r--r--packages/SystemUI/res/values-de/strings.xml21
-rw-r--r--packages/SystemUI/res/values-el/strings.xml21
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml21
-rw-r--r--packages/SystemUI/res/values-es/strings.xml21
-rw-r--r--packages/SystemUI/res/values-et/strings.xml21
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml21
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml23
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml23
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml21
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml21
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml21
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml21
-rw-r--r--packages/SystemUI/res/values-in/strings.xml23
-rw-r--r--packages/SystemUI/res/values-is/strings.xml25
-rw-r--r--packages/SystemUI/res/values-it/strings.xml23
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml21
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml23
-rw-r--r--packages/SystemUI/res/values-km/strings.xml21
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml25
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml23
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml21
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml21
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml21
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml23
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml21
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml23
-rw-r--r--packages/SystemUI/res/values-my/strings.xml21
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml21
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml21
-rw-r--r--packages/SystemUI/res/values-or/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml21
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml21
-rw-r--r--packages/SystemUI/res/values-si/strings.xml21
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml21
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml21
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml21
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml21
-rw-r--r--packages/SystemUI/res/values-te/strings.xml21
-rw-r--r--packages/SystemUI/res/values-th/strings.xml21
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml21
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml21
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml21
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml21
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml21
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml21
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml21
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml23
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml23
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml21
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java265
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java275
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java12
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java55
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java196
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java73
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java56
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java40
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java244
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java275
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java350
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java349
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java147
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java113
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java66
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java550
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java379
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java19
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java30
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java58
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java107
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java148
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java324
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java350
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java394
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java413
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/NumPadKey.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/ViewController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java122
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java87
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java55
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt84
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt59
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java79
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java130
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java62
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java102
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java105
-rw-r--r--packages/Tethering/jni/android_net_util_TetheringUtils.cpp52
-rw-r--r--packages/Tethering/src/android/net/ip/DadProxy.java54
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java45
-rw-r--r--packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java180
-rw-r--r--packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java16
-rw-r--r--packages/Tethering/src/android/net/util/TetheringUtils.java33
-rw-r--r--packages/Tethering/tests/privileged/Android.bp21
-rw-r--r--packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java338
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java91
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java3
-rw-r--r--services/core/java/android/os/BatteryStatsInternal.java7
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java15
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java5
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java47
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java13
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java12
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java11
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java99
-rw-r--r--services/core/java/com/android/server/am/UserController.java22
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java82
-rw-r--r--services/core/java/com/android/server/appop/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java11
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java1
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java24
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java169
-rw-r--r--services/core/java/com/android/server/notification/NotificationShellCmd.java21
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java10
-rw-r--r--services/core/java/com/android/server/pm/Settings.java230
-rw-r--r--services/core/java/com/android/server/pm/permission/AppIdPermissionState.java320
-rw-r--r--services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java44
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java230
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionsState.java970
-rw-r--r--services/core/java/com/android/server/pm/permission/TEST_MAPPING17
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java6
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java20
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java2
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateDenylist.java (renamed from services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java)38
-rw-r--r--services/core/java/com/android/server/wm/RefreshRatePolicy.java8
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java17
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java208
-rw-r--r--services/incremental/IncrementalService.cpp3
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java122
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java31
-rw-r--r--services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java3
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java117
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java (renamed from services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java)94
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java2
-rw-r--r--tools/validatekeymaps/Main.cpp10
-rw-r--r--wifi/api/current.txt6
-rw-r--r--wifi/api/system-current.txt2
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java7
-rw-r--r--wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java59
406 files changed, 9717 insertions, 7562 deletions
diff --git a/Android.bp b/Android.bp
index c6f9362b4919..59530079d4ad 100644
--- a/Android.bp
+++ b/Android.bp
@@ -547,6 +547,7 @@ java_library {
exclude_srcs: ["core/java/android/content/pm/AndroidTestBaseUpdater.java"],
aidl: {
generate_get_transaction_name: true,
+ local_include_dirs: ["media/aidl"],
},
dxflags: [
"--core-library",
@@ -583,6 +584,7 @@ java_library {
// in favor of an API stubs dependency in java_library "framework" below.
"mimemap",
"mediatranscoding_aidl_interface-java",
+ "soundtrigger_middleware-aidl-java",
],
// For backwards compatibility.
stem: "framework",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ca921ff97c35..c82fee0fe8ac 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -83,6 +83,10 @@ stubs_defaults {
merge_annotations_dirs: [
"metalava-manual",
],
+ // TODO(b/169090544): remove below aidl includes.
+ aidl: {
+ local_include_dirs: ["media/aidl"],
+ },
}
droidstubs {
@@ -150,6 +154,10 @@ doc_defaults {
":current-support-api",
":current-androidx-api",
],
+ // TODO(b/169090544): remove below aidl includes.
+ aidl: {
+ local_include_dirs: ["media/aidl"],
+ },
}
doc_defaults {
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index fc5efc6e03ac..7a8d1a1caf25 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -11,6 +11,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
libs/input/
services/core/jni/
services/incremental/
+ tools/
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index bb6538739c49..852fcc6128c4 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -51,9 +51,12 @@ stubs_defaults {
":android_icu4j_public_api_files",
"**/package.html",
],
- // TODO(b/147699819): remove below aidl includes.
+ // TODO(b/147699819, b/169090544): remove below aidl includes.
aidl: {
- local_include_dirs: ["telephony/java"],
+ local_include_dirs: [
+ "telephony/java",
+ "media/aidl",
+ ],
},
libs: ["framework-internal-utils"],
installable: false,
@@ -488,29 +491,3 @@ java_library_static {
":hwbinder-stubs-docs",
],
}
-
-/////////////////////////////////////////////////////////////////////
-// api/*-current.txt files for use by modules in other directories
-// like the CTS test
-/////////////////////////////////////////////////////////////////////
-
-filegroup {
- name: "frameworks-base-api-current.txt",
- srcs: [
- "api/current.txt",
- ],
-}
-
-filegroup {
- name: "frameworks-base-api-system-current.txt",
- srcs: [
- "api/system-current.txt",
- ],
-}
-
-filegroup {
- name: "frameworks-base-api-system-removed.txt",
- srcs: [
- "api/system-removed.txt",
- ],
-}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index b638fef36a9e..4512d77e650e 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2590,13 +2590,14 @@ public class JobSchedulerService extends com.android.server.SystemService
// job that runs one of the app's services, as well as verifying that the
// named service properly requires the BIND_JOB_SERVICE permission
private void enforceValidJobRequest(int uid, JobInfo job) {
- final IPackageManager pm = AppGlobals.getPackageManager();
+ final PackageManager pm = getContext()
+ .createContextAsUser(UserHandle.getUserHandleForUid(uid), 0)
+ .getPackageManager();
final ComponentName service = job.getService();
try {
ServiceInfo si = pm.getServiceInfo(service,
PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- UserHandle.getUserId(uid));
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
@@ -2608,8 +2609,10 @@ public class JobSchedulerService extends com.android.server.SystemService
throw new IllegalArgumentException("Scheduled service " + service
+ " does not require android.permission.BIND_JOB_SERVICE permission");
}
- } catch (RemoteException e) {
- // Can't happen; the Package Manager is in this same process
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException(
+ "Tried to schedule job for non-existent package: "
+ + service.getPackageName());
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
index 47ebf32fa875..999c53fb7daf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
@@ -18,16 +18,15 @@ package com.android.server.job.controllers;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.AppGlobals;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.net.Uri;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -116,10 +115,15 @@ public class ComponentController extends StateController {
ServiceInfo si = mServiceInfoCache.get(userId, service);
if (si == null) {
try {
- si = AppGlobals.getPackageManager().getServiceInfo(
- service, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
+ // createContextAsUser may potentially be expensive
+ // TODO: cache user context or improve ContextImpl implementation if this becomes
+ // a problem
+ si = mContext.createContextAsUser(UserHandle.of(userId), 0)
+ .getPackageManager()
+ .getServiceInfo(service, PackageManager.MATCH_DIRECT_BOOT_AUTO);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Job exists for non-existent package: " + service.getPackageName());
+ return null;
}
mServiceInfoCache.add(userId, service, si);
}
diff --git a/api/Android.bp b/api/Android.bp
index 54ff82c97e17..cb6d448caf63 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -1,7 +1,97 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_visibility: ["//visibility:private"],
+}
+
+// *-current.txt files for use by modules in other directories like cts
+filegroup {
+ name: "frameworks-base-api-current.txt",
+ srcs: ["current.txt"],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "frameworks-base-api-system-current.txt",
+ srcs: ["system-current.txt"],
+ visibility: ["//visibility:public"],
+}
+
+filegroup {
+ name: "frameworks-base-api-system-removed.txt",
+ srcs: ["system-removed.txt"],
+ visibility: ["//visibility:public"],
+}
+
genrule {
name: "current-api-xml",
tools: ["metalava"],
srcs: ["current.txt"],
out: ["current.api"],
cmd: "$(location metalava) --no-banner -convert2xmlnostrip $(in) $(out)",
+ visibility: ["//visibility:public"],
+}
+
+genrule {
+ name: "frameworks-base-api-current-merged.txt",
+ srcs: [
+ ":conscrypt.module.public.api{.public.api.txt}",
+ ":framework-media{.public.api.txt}",
+ ":framework-mediaprovider{.public.api.txt}",
+ ":framework-permission{.public.api.txt}",
+ ":framework-sdkextensions{.public.api.txt}",
+ ":framework-statsd{.public.api.txt}",
+ ":framework-tethering{.public.api.txt}",
+ ":framework-wifi{.public.api.txt}",
+ ":non-updatable-current.txt",
+ ],
+ out: ["current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+ name: "frameworks-base-api-system-current-merged.txt",
+ srcs: [
+ ":framework-media{.system.api.txt}",
+ ":framework-mediaprovider{.system.api.txt}",
+ ":framework-permission{.system.api.txt}",
+ ":framework-sdkextensions{.system.api.txt}",
+ ":framework-statsd{.system.api.txt}",
+ ":framework-tethering{.system.api.txt}",
+ ":framework-wifi{.system.api.txt}",
+ ":non-updatable-system-current.txt",
+ ],
+ out: ["system-current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
+}
+
+genrule {
+ name: "frameworks-base-api-module-lib-current-merged.txt",
+ srcs: [
+ ":framework-media{.module-lib.api.txt}",
+ ":framework-mediaprovider{.module-lib.api.txt}",
+ ":framework-permission{.module-lib.api.txt}",
+ ":framework-sdkextensions{.module-lib.api.txt}",
+ ":framework-statsd{.module-lib.api.txt}",
+ ":framework-tethering{.module-lib.api.txt}",
+ ":framework-wifi{.module-lib.api.txt}",
+ ":non-updatable-module-lib-current.txt",
+ ],
+ out: ["module-lib-current.txt"],
+ tools: ["metalava"],
+ cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
}
diff --git a/api/current.txt b/api/current.txt
index 4590325cb771..c0dbdef4ab42 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+ field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -14292,6 +14293,7 @@ package android.graphics {
public final class BlurShader extends android.graphics.Shader {
ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader, @NonNull android.graphics.Shader.TileMode);
}
public class Camera {
@@ -15195,6 +15197,20 @@ package android.graphics {
ctor public PaintFlagsDrawFilter(int, int);
}
+ public final class ParcelableColorSpace extends android.graphics.ColorSpace implements android.os.Parcelable {
+ ctor public ParcelableColorSpace(@NonNull android.graphics.ColorSpace);
+ method public int describeContents();
+ method @NonNull public float[] fromXyz(@NonNull float[]);
+ method @NonNull public android.graphics.ColorSpace getColorSpace();
+ method public float getMaxValue(int);
+ method public float getMinValue(int);
+ method public static boolean isParcelable(@NonNull android.graphics.ColorSpace);
+ method public boolean isWideGamut();
+ method @NonNull public float[] toXyz(@NonNull float[]);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.graphics.ParcelableColorSpace> CREATOR;
+ }
+
public class Path {
ctor public Path();
ctor public Path(@Nullable android.graphics.Path);
@@ -15630,6 +15646,7 @@ package android.graphics {
public enum Shader.TileMode {
enum_constant public static final android.graphics.Shader.TileMode CLAMP;
+ enum_constant public static final android.graphics.Shader.TileMode DECAL;
enum_constant public static final android.graphics.Shader.TileMode MIRROR;
enum_constant public static final android.graphics.Shader.TileMode REPEAT;
}
@@ -24913,6 +24930,10 @@ package android.media {
method public double getAttributeDouble(@NonNull String, double);
method public int getAttributeInt(@NonNull String, int);
method @Nullable public long[] getAttributeRange(@NonNull String);
+ method public long getDateTime();
+ method public long getDateTimeDigitized();
+ method public long getDateTimeOriginal();
+ method public long getGpsDateTime();
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
method public android.graphics.Bitmap getThumbnailBitmap();
@@ -32009,9 +32030,15 @@ package android.net.wifi.hotspot2.pps {
method public int describeContents();
method public String getFqdn();
method public String getFriendlyName();
+ method @Nullable public long[] getMatchAllOis();
+ method @Nullable public long[] getMatchAnyOis();
+ method @Nullable public String[] getOtherHomePartners();
method public long[] getRoamingConsortiumOis();
method public void setFqdn(String);
method public void setFriendlyName(String);
+ method public void setMatchAllOis(@Nullable long[]);
+ method public void setMatchAnyOis(@Nullable long[]);
+ method public void setOtherHomePartners(@Nullable String[]);
method public void setRoamingConsortiumOis(long[]);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index ab8944277e9a..d27f5a5c006e 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -66,6 +66,7 @@ package android.media.session {
}
public final class MediaSessionManager {
+ method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index c4f9067b507d..118184df9d00 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4399,6 +4399,8 @@ package android.media {
}
public static final class MediaTranscodeManager.TranscodingRequest {
+ method public int getClientPid();
+ method public int getClientUid();
method @NonNull public android.net.Uri getDestinationUri();
method public int getPriority();
method @NonNull public android.net.Uri getSourceUri();
@@ -4409,6 +4411,8 @@ package android.media {
public static final class MediaTranscodeManager.TranscodingRequest.Builder {
ctor public MediaTranscodeManager.TranscodingRequest.Builder();
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
@@ -7424,7 +7428,7 @@ package android.net.wifi {
field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
field public static final String EXTRA_CHANGE_REASON = "changeReason";
- field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+ field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/api/test-current.txt b/api/test-current.txt
index 5082c57cd221..128e84f59048 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -997,6 +997,7 @@ package android.content.pm {
method public void setEnableRollback(boolean, int);
method @RequiresPermission("android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS") public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
+ method public void setInstallAsInstantApp(boolean);
method public void setInstallerPackageName(@Nullable String);
method public void setRequestDowngrade(boolean);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
@@ -1852,6 +1853,8 @@ package android.media {
}
public static final class MediaTranscodeManager.TranscodingRequest {
+ method public int getClientPid();
+ method public int getClientUid();
method @NonNull public android.net.Uri getDestinationUri();
method public int getPriority();
method @NonNull public android.net.Uri getSourceUri();
@@ -1862,6 +1865,8 @@ package android.media {
public static final class MediaTranscodeManager.TranscodingRequest.Builder {
ctor public MediaTranscodeManager.TranscodingRequest.Builder();
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 9c796128df84..046145f90808 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -482,6 +482,8 @@ status_t BootAnimation::readyToRun() {
mFlingerSurface = s;
mTargetInset = -1;
+ projectSceneToWindow();
+
// Register a display event receiver
mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();
status_t status = mDisplayEventReceiver->initCheck();
@@ -493,6 +495,16 @@ status_t BootAnimation::readyToRun() {
return NO_ERROR;
}
+void BootAnimation::projectSceneToWindow() {
+ glViewport(0, 0, mWidth, mHeight);
+ glScissor(0, 0, mWidth, mHeight);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrthof(0, static_cast<float>(mWidth), 0, static_cast<float>(mHeight), -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
// We assume this function is called on the animation thread.
if (newWidth == mWidth && newHeight == mHeight) {
@@ -517,8 +529,8 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) {
SLOGE("Can't make the new surface current. Error %d", eglGetError());
return;
}
- glViewport(0, 0, mWidth, mHeight);
- glScissor(0, 0, mWidth, mHeight);
+
+ projectSceneToWindow();
mSurface = surface;
}
@@ -799,6 +811,37 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
return status;
}
+void BootAnimation::fadeFrame(const int frameLeft, const int frameBottom, const int frameWidth,
+ const int frameHeight, const Animation::Part& part,
+ const int fadedFramesCount) {
+ glEnable(GL_BLEND);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ // avoid creating a hole due to mixing result alpha with GL_REPLACE texture
+ glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
+
+ const float alpha = static_cast<float>(fadedFramesCount) / part.framesToFadeCount;
+ glColor4f(part.backgroundColor[0], part.backgroundColor[1], part.backgroundColor[2], alpha);
+
+ const float frameStartX = static_cast<float>(frameLeft);
+ const float frameStartY = static_cast<float>(frameBottom);
+ const float frameEndX = frameStartX + frameWidth;
+ const float frameEndY = frameStartY + frameHeight;
+ const GLfloat frameRect[] = {
+ frameStartX, frameStartY,
+ frameEndX, frameStartY,
+ frameEndX, frameEndY,
+ frameStartX, frameEndY
+ };
+ glVertexPointer(2, GL_FLOAT, 0, frameRect);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisable(GL_BLEND);
+}
+
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name);
@@ -890,23 +933,34 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
int height = 0;
int count = 0;
int pause = 0;
+ int framesToFadeCount = 0;
char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
char clockPos2[TEXT_POS_LEN_MAX + 1] = "";
-
char pathType;
+
+ int nextReadPos;
+
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
// SLOGD("> w=%d, h=%d, fps=%d", width, height, fps);
animation.width = width;
animation.height = height;
animation.fps = fps;
- } else if (sscanf(l, " %c %d %d %" STRTO(ANIM_PATH_MAX) "s #%6s %16s %16s",
- &pathType, &count, &pause, path, color, clockPos1, clockPos2) >= 4) {
- //SLOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s, clockPos1=%s, clockPos2=%s",
- // pathType, count, pause, path, color, clockPos1, clockPos2);
+ } else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
+ &pathType, &count, &pause, path, &nextReadPos) >= 4) {
+ if (pathType == 'f') {
+ sscanf(l + nextReadPos, " %d #%6s %16s %16s", &framesToFadeCount, color, clockPos1,
+ clockPos2);
+ } else {
+ sscanf(l + nextReadPos, " #%6s %16s %16s", color, clockPos1, clockPos2);
+ }
+ // SLOGD("> type=%c, count=%d, pause=%d, path=%s, framesToFadeCount=%d, color=%s, "
+ // "clockPos1=%s, clockPos2=%s",
+ // pathType, count, pause, path, framesToFadeCount, color, clockPos1, clockPos2);
Animation::Part part;
part.playUntilComplete = pathType == 'c';
+ part.framesToFadeCount = framesToFadeCount;
part.count = count;
part.pause = pause;
part.path = path;
@@ -925,6 +979,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
// SLOGD("> SYSTEM");
Animation::Part part;
part.playUntilComplete = false;
+ part.framesToFadeCount = 0;
part.count = 1;
part.pause = 0;
part.audioData = nullptr;
@@ -1121,12 +1176,19 @@ bool BootAnimation::movie() {
return false;
}
+bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part, const int fadedFramesCount) {
+ // stop playing only if it is time to exit and it's a partial part which has been faded out
+ return exitPending() && !part.playUntilComplete && fadedFramesCount >= part.framesToFadeCount;
+}
+
bool BootAnimation::playAnimation(const Animation& animation) {
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
elapsedRealtime());
+
+ int fadedFramesCount = 0;
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
@@ -1140,10 +1202,9 @@ bool BootAnimation::playAnimation(const Animation& animation) {
continue; //to next part
}
- for (int r=0 ; !part.count || r<part.count ; r++) {
- // Exit any non playuntil complete parts immediately
- if(exitPending() && !part.playUntilComplete)
- break;
+ // process the part not only while the count allows but also if already fading
+ for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {
+ if (shouldStopPlayingPart(part, fadedFramesCount)) break;
mCallbacks->playPart(i, part, r);
@@ -1153,7 +1214,9 @@ bool BootAnimation::playAnimation(const Animation& animation) {
part.backgroundColor[2],
1.0f);
- for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
+ for (size_t j=0 ; j<fcount ; j++) {
+ if (shouldStopPlayingPart(part, fadedFramesCount)) break;
+
processDisplayEvents();
const int animationX = (mWidth - animation.width) / 2;
@@ -1192,11 +1255,22 @@ bool BootAnimation::playAnimation(const Animation& animation) {
}
// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)
// which is equivalent to mHeight - (yc + frame.trimHeight)
- glDrawTexiOES(xc, mHeight - (yc + frame.trimHeight),
- 0, frame.trimWidth, frame.trimHeight);
+ const int frameDrawY = mHeight - (yc + frame.trimHeight);
+ glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);
+
+ // if the part hasn't been stopped yet then continue fading if necessary
+ if (exitPending() && part.hasFadingPhase()) {
+ fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,
+ ++fadedFramesCount);
+ if (fadedFramesCount >= part.framesToFadeCount) {
+ fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading
+ }
+ }
+
if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
}
+
handleViewport(frameDuration);
eglSwapBuffers(mDisplay, mSurface);
@@ -1221,11 +1295,11 @@ bool BootAnimation::playAnimation(const Animation& animation) {
usleep(part.pause * ns2us(frameDuration));
- // For infinite parts, we've now played them at least once, so perhaps exit
- if(exitPending() && !part.count && mCurrentInset >= mTargetInset)
- break;
+ if (exitPending() && !part.count && mCurrentInset >= mTargetInset &&
+ !part.hasFadingPhase()) {
+ break; // exit the infinite non-fading part when it has been played at least once
+ }
}
-
}
// Free textures created for looping parts now that the animation is done.
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 9e6e4aa42f1c..4699cfe2ac2d 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -19,6 +19,7 @@
#include <vector>
#include <queue>
+#include <climits>
#include <stdint.h>
#include <sys/types.h>
@@ -43,6 +44,8 @@ class SurfaceControl;
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
+ static constexpr int MAX_FADED_FRAMES_COUNT = std::numeric_limits<int>::max();
+
struct Texture {
GLint w;
GLint h;
@@ -82,10 +85,15 @@ public:
String8 trimData;
SortedVector<Frame> frames;
bool playUntilComplete;
+ int framesToFadeCount;
float backgroundColor[3];
uint8_t* audioData;
int audioLength;
Animation* animation;
+
+ bool hasFadingPhase() const {
+ return !playUntilComplete && framesToFadeCount > 0;
+ }
};
int fps;
int width;
@@ -160,6 +168,8 @@ private:
bool movie();
void drawText(const char* str, const Font& font, bool bold, int* x, int* y);
void drawClock(const Font& font, const int xPos, const int yPos);
+ void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight,
+ const Animation::Part& part, int fadedFramesCount);
bool validClock(const Animation::Part& part);
Animation* loadAnimation(const String8&);
bool playAnimation(const Animation&);
@@ -172,7 +182,9 @@ private:
EGLConfig getEglConfig(const EGLDisplay&);
ui::Size limitSurfaceSize(int width, int height) const;
void resizeSurface(int newWidth, int newHeight);
+ void projectSceneToWindow();
+ bool shouldStopPlayingPart(const Animation::Part& part, int fadedFramesCount);
void checkExit();
void handleViewport(nsecs_t timestep);
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 5946515aa263..f9b83c957d5b 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -30,14 +30,20 @@ The first line defines the general parameters of the animation:
It is followed by a number of rows of the form:
- TYPE COUNT PAUSE PATH [#RGBHEX [CLOCK1 [CLOCK2]]]
+ TYPE COUNT PAUSE PATH [FADE [#RGBHEX [CLOCK1 [CLOCK2]]]]
* **TYPE:** a single char indicating what type of animation segment this is:
+ `p` -- this part will play unless interrupted by the end of the boot
+ `c` -- this part will play to completion, no matter what
+ + `f` -- same as `p` but in addition the specified number of frames is being faded out while
+ continue playing. Only the first interrupted `f` part is faded out, other subsequent `f`
+ parts are skipped
* **COUNT:** how many times to play the animation, or 0 to loop forever until boot is complete
* **PAUSE:** number of FRAMES to delay after this part ends
* **PATH:** directory in which to find the frames for this part (e.g. `part0`)
+ * **FADE:** _(ONLY FOR `f` TYPE)_ number of frames to fade out when interrupted where `0` means
+ _immediately_ which makes `f ... 0` behave like `p` and doesn't count it as a fading
+ part
* **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB`
* **CLOCK1, CLOCK2:** _(OPTIONAL)_ the coordinates at which to draw the current time (for watches):
+ If only `CLOCK1` is provided it is the y-coordinate of the clock and the x-coordinate
diff --git a/cmds/statsd/src/condition/ConditionTimer.h b/cmds/statsd/src/condition/ConditionTimer.h
index 442bc11934fe..1fbe25279736 100644
--- a/cmds/statsd/src/condition/ConditionTimer.h
+++ b/cmds/statsd/src/condition/ConditionTimer.h
@@ -36,7 +36,7 @@ class ConditionTimer {
public:
explicit ConditionTimer(bool initCondition, int64_t bucketStartNs) : mCondition(initCondition) {
if (initCondition) {
- mLastConditionTrueTimestampNs = bucketStartNs;
+ mLastConditionChangeTimestampNs = bucketStartNs;
}
};
@@ -44,21 +44,46 @@ public:
// When a new bucket is created, this value will be reset to 0.
int64_t mTimerNs = 0;
- // Last elapsed real timestamp when condition turned to true
- // When a new bucket is created and the condition is true, then the timestamp is set
- // to be the bucket start timestamp.
- int64_t mLastConditionTrueTimestampNs = 0;
+ // Last elapsed real timestamp when condition changed.
+ int64_t mLastConditionChangeTimestampNs = 0;
bool mCondition = false;
int64_t newBucketStart(int64_t nextBucketStartNs) {
if (mCondition) {
- mTimerNs += (nextBucketStartNs - mLastConditionTrueTimestampNs);
- mLastConditionTrueTimestampNs = nextBucketStartNs;
+ // Normally, the next bucket happens after the last condition
+ // change. In this case, add the time between the condition becoming
+ // true to the next bucket start time.
+ // Otherwise, the next bucket start time is before the last
+ // condition change time, this means that the condition was false at
+ // the bucket boundary before the condition became true, so the
+ // timer should not get updated and the last condition change time
+ // remains as is.
+ if (nextBucketStartNs >= mLastConditionChangeTimestampNs) {
+ mTimerNs += (nextBucketStartNs - mLastConditionChangeTimestampNs);
+ mLastConditionChangeTimestampNs = nextBucketStartNs;
+ }
+ } else if (mLastConditionChangeTimestampNs > nextBucketStartNs) {
+ // The next bucket start time is before the last condition change
+ // time, this means that the condition was true at the bucket
+ // boundary before the condition became false, so adjust the timer
+ // to match how long the condition was true to the bucket boundary.
+ // This means remove the amount the condition stayed true in the
+ // next bucket from the current bucket.
+ mTimerNs -= (mLastConditionChangeTimestampNs - nextBucketStartNs);
}
int64_t temp = mTimerNs;
mTimerNs = 0;
+
+ if (!mCondition && (mLastConditionChangeTimestampNs > nextBucketStartNs)) {
+ // The next bucket start time is before the last condition change
+ // time, this means that the condition was true at the bucket
+ // boundary and remained true in the next bucket up to the condition
+ // change to false, so adjust the timer to match how long the
+ // condition stayed true in the next bucket (now the current bucket).
+ mTimerNs = mLastConditionChangeTimestampNs - nextBucketStartNs;
+ }
return temp;
}
@@ -67,11 +92,10 @@ public:
return;
}
mCondition = newCondition;
- if (newCondition) {
- mLastConditionTrueTimestampNs = timestampNs;
- } else {
- mTimerNs += (timestampNs - mLastConditionTrueTimestampNs);
+ if (newCondition == false) {
+ mTimerNs += (timestampNs - mLastConditionChangeTimestampNs);
}
+ mLastConditionChangeTimestampNs = timestampNs;
}
FRIEND_TEST(ConditionTimerTest, TestTimer_Inital_False);
@@ -80,4 +104,4 @@ public:
} // namespace statsd
} // namespace os
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 39ae9a47f2bf..3d57cfe318c5 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -301,7 +301,6 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->write(FIELD_TYPE_INT32 | FIELD_ID_BUCKET_DROP_REASON, dropEvent.reason);
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_DROP_TIME,
(long long)(NanoToMillis(dropEvent.dropTimeNs)));
- ;
protoOutput->end(dropEventToken);
}
protoOutput->end(wrapperToken);
@@ -346,8 +345,11 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_NUM,
(long long)(getBucketNumFromEndTimeNs(bucket.mBucketEndNs)));
}
- // only write the condition timer value if the metric has a condition.
- if (mConditionTrackerIndex >= 0) {
+ // We only write the condition timer value if the metric has a
+ // condition and/or is sliced by state.
+ // If the metric is sliced by state, the condition timer value is
+ // also sliced by state to reflect time spent in that state.
+ if (mConditionTrackerIndex >= 0 || !mSlicedStateAtoms.empty()) {
protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_TRUE_NS,
(long long)bucket.mConditionTrueNs);
}
@@ -454,6 +456,8 @@ void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs)
// Let condition timer know of new active state.
mConditionTimer.onConditionChanged(mIsActive, eventTimeNs);
+
+ updateCurrentSlicedBucketConditionTimers(mIsActive, eventTimeNs);
}
void ValueMetricProducer::onConditionChangedLocked(const bool condition,
@@ -476,6 +480,8 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
invalidateCurrentBucket(eventTimeNs, BucketDropReason::EVENT_IN_WRONG_BUCKET);
mCondition = ConditionState::kUnknown;
mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+
+ updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
return;
}
@@ -517,6 +523,29 @@ void ValueMetricProducer::onConditionChangedLocked(const bool condition,
flushIfNeededLocked(eventTimeNs);
mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+
+ updateCurrentSlicedBucketConditionTimers(mCondition, eventTimeNs);
+}
+
+void ValueMetricProducer::updateCurrentSlicedBucketConditionTimers(bool newCondition,
+ int64_t eventTimeNs) {
+ if (mSlicedStateAtoms.empty()) {
+ return;
+ }
+
+ // Utilize the current state key of each DimensionsInWhat key to determine
+ // which condition timers to update.
+ //
+ // Assumes that the MetricDimensionKey exists in `mCurrentSlicedBucket`.
+ bool inPulledData;
+ for (const auto& [dimensionInWhatKey, dimensionInWhatInfo] : mCurrentBaseInfo) {
+ // If the new condition is true, turn ON the condition timer only if
+ // the DimensionInWhat key was present in the pulled data.
+ inPulledData = dimensionInWhatInfo.hasCurrentState;
+ mCurrentSlicedBucket[MetricDimensionKey(dimensionInWhatKey,
+ dimensionInWhatInfo.currentState)]
+ .conditionTimer.onConditionChanged(newCondition && inPulledData, eventTimeNs);
+ }
}
void ValueMetricProducer::prepareFirstBucketLocked() {
@@ -618,8 +647,8 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log
// 2. A superset of the current mStateChangePrimaryKey
// was not found in the new pulled data (i.e. not in mMatchedDimensionInWhatKeys)
// then we need to reset the base.
- for (auto& slice : mCurrentSlicedBucket) {
- const auto& whatKey = slice.first.getDimensionKeyInWhat();
+ for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+ const auto& whatKey = metricDimensionKey.getDimensionKeyInWhat();
bool presentInPulledData =
mMatchedMetricDimensionKeys.find(whatKey) != mMatchedMetricDimensionKeys.end();
if (!presentInPulledData && whatKey.contains(mStateChangePrimaryKey.second)) {
@@ -627,6 +656,12 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log
for (auto& baseInfo : it->second.baseInfos) {
baseInfo.hasBase = false;
}
+ // Set to false when DimensionInWhat key is not present in a pull.
+ // Used in onMatchedLogEventInternalLocked() to ensure the condition
+ // timer is turned on the next pull when data is present.
+ it->second.hasCurrentState = false;
+ // Turn OFF condition timer for keys not present in pulled data.
+ currentValueBucket.conditionTimer.onConditionChanged(false, eventElapsedTimeNs);
}
}
mMatchedMetricDimensionKeys.clear();
@@ -789,21 +824,26 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
return;
}
- DimensionsInWhatInfo& dimensionsInWhatInfo = mCurrentBaseInfo[whatKey];
+ const auto& returnVal =
+ mCurrentBaseInfo.emplace(whatKey, DimensionsInWhatInfo(getUnknownStateKey()));
+ DimensionsInWhatInfo& dimensionsInWhatInfo = returnVal.first->second;
+ const HashableDimensionKey oldStateKey = dimensionsInWhatInfo.currentState;
vector<BaseInfo>& baseInfos = dimensionsInWhatInfo.baseInfos;
if (baseInfos.size() < mFieldMatchers.size()) {
VLOG("Resizing number of intervals to %d", (int)mFieldMatchers.size());
baseInfos.resize(mFieldMatchers.size());
}
+ // Ensure we turn on the condition timer in the case where dimensions
+ // were missing on a previous pull due to a state change.
+ bool stateChange = oldStateKey != stateKey;
if (!dimensionsInWhatInfo.hasCurrentState) {
- dimensionsInWhatInfo.currentState = getUnknownStateKey();
+ stateChange = true;
dimensionsInWhatInfo.hasCurrentState = true;
}
// We need to get the intervals stored with the previous state key so we can
// close these value intervals.
- const auto oldStateKey = dimensionsInWhatInfo.currentState;
vector<Interval>& intervals =
mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)].intervals;
if (intervals.size() < mFieldMatchers.size()) {
@@ -916,6 +956,17 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
interval.sampleSize += 1;
}
+ // State change.
+ if (!mSlicedStateAtoms.empty() && stateChange) {
+ // Turn OFF the condition timer for the previous state key.
+ mCurrentSlicedBucket[MetricDimensionKey(whatKey, oldStateKey)]
+ .conditionTimer.onConditionChanged(false, eventTimeNs);
+
+ // Turn ON the condition timer for the new state key.
+ mCurrentSlicedBucket[MetricDimensionKey(whatKey, stateKey)]
+ .conditionTimer.onConditionChanged(true, eventTimeNs);
+ }
+
// Only trigger the tracker if all intervals are correct and we have not skipped the bucket due
// to MULTIPLE_BUCKETS_SKIPPED.
if (useAnomalyDetection && !multipleBucketsSkipped(calcBucketsForwardCount(eventTimeNs))) {
@@ -990,12 +1041,18 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
if (!mCurrentBucketIsSkipped) {
bool bucketHasData = false;
// The current bucket is large enough to keep.
- for (const auto& slice : mCurrentSlicedBucket) {
- PastValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second.intervals);
- bucket.mConditionTrueNs = conditionTrueDuration;
+ for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+ PastValueBucket bucket =
+ buildPartialBucket(bucketEndTime, currentValueBucket.intervals);
+ if (!mSlicedStateAtoms.empty()) {
+ bucket.mConditionTrueNs =
+ currentValueBucket.conditionTimer.newBucketStart(bucketEndTime);
+ } else {
+ bucket.mConditionTrueNs = conditionTrueDuration;
+ }
// it will auto create new vector of ValuebucketInfo if the key is not found.
if (bucket.valueIndex.size() > 0) {
- auto& bucketList = mPastBuckets[slice.first];
+ auto& bucketList = mPastBuckets[metricDimensionKey];
bucketList.push_back(bucket);
bucketHasData = true;
}
@@ -1023,11 +1080,18 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
buildDropEvent(eventTimeNs, BucketDropReason::NO_DATA));
mSkippedBuckets.emplace_back(bucketInGap);
}
-
appendToFullBucket(eventTimeNs > fullBucketEndTimeNs);
initCurrentSlicedBucket(nextBucketStartTimeNs);
// Update the condition timer again, in case we skipped buckets.
mConditionTimer.newBucketStart(nextBucketStartTimeNs);
+
+ // NOTE: Update the condition timers in `mCurrentSlicedBucket` only when slicing
+ // by state. Otherwise, the "global" condition timer will be used.
+ if (!mSlicedStateAtoms.empty()) {
+ for (auto& [metricDimensionKey, currentValueBucket] : mCurrentSlicedBucket) {
+ currentValueBucket.conditionTimer.newBucketStart(nextBucketStartTimeNs);
+ }
+ }
mCurrentBucketNum += numBucketsForward;
}
@@ -1069,6 +1133,17 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs)
interval.seenNewData = false;
}
+ if (obsolete && !mSlicedStateAtoms.empty()) {
+ // When slicing by state, only delete the MetricDimensionKey when the
+ // state key in the MetricDimensionKey is not the current state key.
+ const HashableDimensionKey& dimensionInWhatKey = it->first.getDimensionKeyInWhat();
+ const auto& currentBaseInfoItr = mCurrentBaseInfo.find(dimensionInWhatKey);
+
+ if ((currentBaseInfoItr != mCurrentBaseInfo.end()) &&
+ (it->first.getStateValuesKey() == currentBaseInfoItr->second.currentState)) {
+ obsolete = false;
+ }
+ }
if (obsolete) {
it = mCurrentSlicedBucket.erase(it);
} else {
@@ -1104,7 +1179,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
// Accumulate partial buckets with current value and then send to anomaly tracker.
if (mCurrentFullBucket.size() > 0) {
for (const auto& slice : mCurrentSlicedBucket) {
- if (hitFullBucketGuardRailLocked(slice.first)) {
+ if (hitFullBucketGuardRailLocked(slice.first) || slice.second.intervals.empty()) {
continue;
}
// TODO: fix this when anomaly can accept double values
@@ -1125,7 +1200,7 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
// Skip aggregating the partial buckets since there's no previous partial bucket.
for (const auto& slice : mCurrentSlicedBucket) {
for (auto& tracker : mAnomalyTrackers) {
- if (tracker != nullptr) {
+ if (tracker != nullptr && !slice.second.intervals.empty()) {
// TODO: fix this when anomaly can accept double values
auto& interval = slice.second.intervals[0];
if (interval.hasValue) {
@@ -1139,10 +1214,12 @@ void ValueMetricProducer::appendToFullBucket(const bool isFullBucketReached) {
} else {
// Accumulate partial bucket.
for (const auto& slice : mCurrentSlicedBucket) {
- // TODO: fix this when anomaly can accept double values
- auto& interval = slice.second.intervals[0];
- if (interval.hasValue) {
- mCurrentFullBucket[slice.first] += interval.value.long_value;
+ if (!slice.second.intervals.empty()) {
+ // TODO: fix this when anomaly can accept double values
+ auto& interval = slice.second.intervals[0];
+ if (interval.hasValue) {
+ mCurrentFullBucket[slice.first] += interval.value.long_value;
+ }
}
}
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 4b2599bdb517..67de214e655c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -193,8 +193,14 @@ private:
// Internal state of an ongoing aggregation bucket.
typedef struct CurrentValueBucket {
+ // If the `MetricDimensionKey` state key is the current state key, then
+ // the condition timer will be updated later (e.g. condition/state/active
+ // state change) with the correct condition and time.
+ CurrentValueBucket() : intervals(), conditionTimer(ConditionTimer(false, 0)) {}
// Value information for each value field of the metric.
std::vector<Interval> intervals;
+ // Tracks how long the condition is true.
+ ConditionTimer conditionTimer;
} CurrentValueBucket;
// Holds base information for diffing values from one value field.
@@ -206,7 +212,10 @@ private:
} BaseInfo;
// State key and base information for a specific DimensionsInWhat key.
- typedef struct {
+ typedef struct DimensionsInWhatInfo {
+ DimensionsInWhatInfo(const HashableDimensionKey& stateKey)
+ : baseInfos(), currentState(stateKey), hasCurrentState(false) {
+ }
std::vector<BaseInfo> baseInfos;
// Last seen state value(s).
HashableDimensionKey currentState;
@@ -252,6 +261,10 @@ private:
// Reset diff base and mHasGlobalBase
void resetBase();
+ // Updates the condition timers in the current sliced bucket when there is a
+ // condition change or an active state change.
+ void updateCurrentSlicedBucketConditionTimers(bool newCondition, int64_t eventTimeNs);
+
static const size_t kBucketSize = sizeof(PastValueBucket{});
const size_t mDimensionSoftLimit;
@@ -337,6 +350,11 @@ private:
FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket);
+ FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary);
FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed);
FRIEND_TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed);
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
index 5dbf16deb552..2ae57638791e 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.cpp
@@ -24,6 +24,8 @@
#include "matchers/EventMatcherWizard.h"
#include "metrics_manager_util.h"
+using google::protobuf::MessageLite;
+
namespace android {
namespace os {
namespace statsd {
@@ -419,16 +421,19 @@ bool metricActivationDepsChange(const StatsdConfig& config,
return false;
}
-bool determineEventMetricUpdateStatus(const StatsdConfig& config, const EventMetric& metric,
- const unordered_map<int64_t, int>& oldMetricProducerMap,
- const vector<sp<MetricProducer>>& oldMetricProducers,
- const unordered_map<int64_t, int>& metricToActivationMap,
- const set<int64_t>& replacedMatchers,
- const set<int64_t>& replacedConditions,
- UpdateStatus& updateStatus) {
- int64_t id = metric.id();
+bool determineMetricUpdateStatus(
+ const StatsdConfig& config, const MessageLite& metric, const int64_t metricId,
+ const MetricType metricType, const set<int64_t>& matcherDependencies,
+ const set<int64_t>& conditionDependencies,
+ const ::google::protobuf::RepeatedField<int64_t>& stateDependencies,
+ const ::google::protobuf::RepeatedPtrField<MetricConditionLink>& conditionLinks,
+ const unordered_map<int64_t, int>& oldMetricProducerMap,
+ const vector<sp<MetricProducer>>& oldMetricProducers,
+ const unordered_map<int64_t, int>& metricToActivationMap,
+ const set<int64_t>& replacedMatchers, const set<int64_t>& replacedConditions,
+ const set<int64_t>& replacedStates, UpdateStatus& updateStatus) {
// Check if new metric
- const auto& oldMetricProducerIt = oldMetricProducerMap.find(id);
+ const auto& oldMetricProducerIt = oldMetricProducerMap.find(metricId);
if (oldMetricProducerIt == oldMetricProducerMap.end()) {
updateStatus = UPDATE_NEW;
return true;
@@ -436,41 +441,82 @@ bool determineEventMetricUpdateStatus(const StatsdConfig& config, const EventMet
// This is an existing metric, check if it has changed.
uint64_t metricHash;
- if (!getMetricProtoHash(config, metric, id, metricToActivationMap, metricHash)) {
+ if (!getMetricProtoHash(config, metric, metricId, metricToActivationMap, metricHash)) {
return false;
}
const sp<MetricProducer> oldMetricProducer = oldMetricProducers[oldMetricProducerIt->second];
- if (oldMetricProducer->getMetricType() != METRIC_TYPE_EVENT ||
+ if (oldMetricProducer->getMetricType() != metricType ||
oldMetricProducer->getProtoHash() != metricHash) {
updateStatus = UPDATE_REPLACE;
return true;
}
- // Metric type and definition are the same. Need to check dependencies to see if they changed.
- if (replacedMatchers.find(metric.what()) != replacedMatchers.end()) {
+ // Take intersections of the matchers/predicates/states that the metric
+ // depends on with those that have been replaced. If a metric depends on any
+ // replaced component, it too must be replaced.
+ set<int64_t> intersection;
+ set_intersection(matcherDependencies.begin(), matcherDependencies.end(),
+ replacedMatchers.begin(), replacedMatchers.end(),
+ inserter(intersection, intersection.begin()));
+ if (intersection.size() > 0) {
+ updateStatus = UPDATE_REPLACE;
+ return true;
+ }
+ set_intersection(conditionDependencies.begin(), conditionDependencies.end(),
+ replacedConditions.begin(), replacedConditions.end(),
+ inserter(intersection, intersection.begin()));
+ if (intersection.size() > 0) {
+ updateStatus = UPDATE_REPLACE;
+ return true;
+ }
+ set_intersection(stateDependencies.begin(), stateDependencies.end(), replacedStates.begin(),
+ replacedStates.end(), inserter(intersection, intersection.begin()));
+ if (intersection.size() > 0) {
updateStatus = UPDATE_REPLACE;
return true;
}
- if (metric.has_condition()) {
- if (replacedConditions.find(metric.condition()) != replacedConditions.end()) {
+ for (const auto& metricConditionLink : conditionLinks) {
+ if (replacedConditions.find(metricConditionLink.condition()) != replacedConditions.end()) {
updateStatus = UPDATE_REPLACE;
return true;
}
}
- if (metricActivationDepsChange(config, metricToActivationMap, id, replacedMatchers)) {
+ if (metricActivationDepsChange(config, metricToActivationMap, metricId, replacedMatchers)) {
updateStatus = UPDATE_REPLACE;
return true;
}
- for (const auto& metricConditionLink : metric.links()) {
- if (replacedConditions.find(metricConditionLink.condition()) != replacedConditions.end()) {
- updateStatus = UPDATE_REPLACE;
- return true;
+ updateStatus = UPDATE_PRESERVE;
+ return true;
+}
+
+bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
+ const unordered_map<int64_t, int>& oldMetricProducerMap,
+ const vector<sp<MetricProducer>>& oldMetricProducers,
+ const unordered_map<int64_t, int>& metricToActivationMap,
+ const set<int64_t>& replacedMatchers,
+ const set<int64_t>& replacedConditions,
+ const set<int64_t>& replacedStates,
+ vector<UpdateStatus>& metricsToUpdate) {
+ int metricIndex = 0;
+ for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
+ const EventMetric& metric = config.event_metric(i);
+ set<int64_t> conditionDependencies;
+ if (metric.has_condition()) {
+ conditionDependencies.insert(metric.condition());
+ }
+ if (!determineMetricUpdateStatus(
+ config, metric, metric.id(), METRIC_TYPE_EVENT, {metric.what()},
+ conditionDependencies, ::google::protobuf::RepeatedField<int64_t>(),
+ metric.links(), oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ replacedMatchers, replacedConditions, replacedStates,
+ metricsToUpdate[metricIndex])) {
+ return false;
}
}
- updateStatus = UPDATE_PRESERVE;
+ // TODO: determine update status for count, gauge, value, duration metrics.
return true;
}
@@ -518,22 +564,16 @@ bool updateMetrics(const ConfigKey& key, const StatsdConfig& config, const int64
}
vector<UpdateStatus> metricsToUpdate(allMetricsCount, UPDATE_UNKNOWN);
- int metricIndex = 0;
- for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
- newMetricProducerMap[config.event_metric(i).id()] = metricIndex;
- if (!determineEventMetricUpdateStatus(config, config.event_metric(i), oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions,
- metricsToUpdate[metricIndex])) {
- return false;
- }
+ if (!determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+ metricToActivationMap, replacedMatchers,
+ replacedConditions, replacedStates, metricsToUpdate)) {
+ return false;
}
- // TODO: determine update status for count, gauge, value, duration metrics.
-
// Now, perform the update. Must iterate the metric types in the same order
- metricIndex = 0;
+ int metricIndex = 0;
for (int i = 0; i < config.event_metric_size(); i++, metricIndex++) {
+ newMetricProducerMap[config.event_metric(i).id()] = metricIndex;
const EventMetric& metric = config.event_metric(i);
switch (metricsToUpdate[metricIndex]) {
case UPDATE_PRESERVE: {
diff --git a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
index 1cd0ce524b31..34d7e9c7de9e 100644
--- a/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
+++ b/cmds/statsd/src/metrics/parsing_utils/config_update_utils.h
@@ -125,23 +125,25 @@ bool updateConditions(const ConfigKey& key, const StatsdConfig& config,
std::vector<ConditionState>& conditionCache,
std::set<int64_t>& replacedConditions);
-// Function to determine if an event metric needs to be updated. Populates updateStatus.
+// Function to determine the update status (preserve/replace/new) of all metrics in the config.
// [config]: the input StatsdConfig
-// [metric]: the current metric to be updated
// [oldMetricProducerMap]: metric id to index mapping in the existing MetricsManager
// [oldMetricProducers]: stores the existing MetricProducers
-// [metricToActivationMap]: map from metric id to metric activation index.
-// [replacedMatchers]: set of replaced matcher ids. conditions using these matchers must be replaced
+// [metricToActivationMap]: map from metric id to metric activation index
+// [replacedMatchers]: set of replaced matcher ids. metrics using these matchers must be replaced
+// [replacedConditions]: set of replaced conditions. metrics using these conditions must be replaced
+// [replacedStates]: set of replaced state ids. metrics using these states must be replaced
// output:
-// [updateStatus]: update status for the metric. Will be changed from UPDATE_UNKNOWN after this call
+// [metricsToUpdate]: update status of each metric. Will be changed from UPDATE_UNKNOWN
// Returns whether the function was successful or not.
-bool determineEventMetricUpdateStatus(const StatsdConfig& config, const EventMetric& metric,
+bool determineAllMetricUpdateStatuses(const StatsdConfig& config,
const unordered_map<int64_t, int>& oldMetricProducerMap,
const vector<sp<MetricProducer>>& oldMetricProducers,
const unordered_map<int64_t, int>& metricToActivationMap,
const set<int64_t>& replacedMatchers,
const set<int64_t>& replacedConditions,
- UpdateStatus& updateStatus);
+ const set<int64_t>& replacedStates,
+ vector<UpdateStatus>& metricsToUpdate);
// Update MetricProducers.
// input:
diff --git a/cmds/statsd/tests/condition/ConditionTimer_test.cpp b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
index ea02cd3a5ee1..46dc9a9d381f 100644
--- a/cmds/statsd/tests/condition/ConditionTimer_test.cpp
+++ b/cmds/statsd/tests/condition/ConditionTimer_test.cpp
@@ -35,11 +35,11 @@ TEST(ConditionTimerTest, TestTimer_Inital_False) {
EXPECT_EQ(0, timer.mTimerNs);
timer.onConditionChanged(true, ct_start_time + 5);
- EXPECT_EQ(ct_start_time + 5, timer.mLastConditionTrueTimestampNs);
+ EXPECT_EQ(ct_start_time + 5, timer.mLastConditionChangeTimestampNs);
EXPECT_EQ(true, timer.mCondition);
EXPECT_EQ(95, timer.newBucketStart(ct_start_time + 100));
- EXPECT_EQ(ct_start_time + 100, timer.mLastConditionTrueTimestampNs);
+ EXPECT_EQ(ct_start_time + 100, timer.mLastConditionChangeTimestampNs);
EXPECT_EQ(true, timer.mCondition);
}
@@ -51,7 +51,7 @@ TEST(ConditionTimerTest, TestTimer_Inital_True) {
EXPECT_EQ(ct_start_time - time_base, timer.newBucketStart(ct_start_time));
EXPECT_EQ(true, timer.mCondition);
EXPECT_EQ(0, timer.mTimerNs);
- EXPECT_EQ(ct_start_time, timer.mLastConditionTrueTimestampNs);
+ EXPECT_EQ(ct_start_time, timer.mLastConditionChangeTimestampNs);
timer.onConditionChanged(false, ct_start_time + 5);
EXPECT_EQ(5, timer.mTimerNs);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index b166cc1fe04e..6cf4192b41fd 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -93,6 +93,13 @@ static void assertPastBucketValuesSingleKey(
}
}
+static void assertConditionTimer(const ConditionTimer& conditionTimer, bool condition,
+ int64_t timerNs, int64_t lastConditionTrueTimestampNs) {
+ EXPECT_EQ(condition, conditionTimer.mCondition);
+ EXPECT_EQ(timerNs, conditionTimer.mTimerNs);
+ EXPECT_EQ(lastConditionTrueTimestampNs, conditionTimer.mLastConditionChangeTimestampNs);
+}
+
} // anonymous namespace
class ValueMetricProducerTestHelper {
@@ -3967,33 +3974,37 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
// Screen state change to ON.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
return true;
}))
// Screen state change to OFF.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 9));
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 9));
return true;
}))
// Screen state change to ON.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
return true;
}))
// Dump report requested.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
return true;
}));
@@ -4025,12 +4036,13 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
- bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4040,19 +4052,29 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(0, it->second.intervals.size());
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Bucket status after screen state change ON->OFF.
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4061,13 +4083,23 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
EXPECT_TRUE(itBase->second.hasCurrentState);
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, OFF}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(0, it->second.intervals.size());
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
// Value for dimension, state key {{}, ON}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4076,9 +4108,11 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Bucket status after screen state change OFF->ON.
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
@@ -4098,6 +4132,8 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(12, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 15 * NS_PER_SEC);
// Value for dimension, state key {{}, ON}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4106,6 +4142,8 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, true, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 15 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4114,37 +4152,46 @@ TEST(ValueMetricProducerTest, TestSlicedState) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Start dump report and check output.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
- NO_TIME_CONSTRAINTS, &strSet, &output);
+ valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
ASSERT_EQ(3, report.value_metrics().data_size());
+ // {{}, kStateUnknown}
auto data = report.value_metrics().data(0);
ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {{}, ON}
data = report.value_metrics().data(1);
ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(13, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+ EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {{}, OFF}
data = report.value_metrics().data(2);
ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(12, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+ EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
}
/*
@@ -4169,9 +4216,10 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Screen state change to ON.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 5 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5, 5));
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 5 * NS_PER_SEC, 5));
return true;
}))
// Screen state change to VR has no pull because it is in the same
@@ -4183,17 +4231,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
// Screen state change to OFF.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 15 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 15, 21));
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 15 * NS_PER_SEC, 21));
return true;
}))
// Dump report requested.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
data->clear();
- data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 50, 30));
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 30));
return true;
}));
@@ -4236,12 +4286,13 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
// Bucket status after screen state change kStateUnknown->ON.
auto screenEvent = CreateScreenStateChangedEvent(
- bucketStartTimeNs + 5, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ bucketStartTimeNs + 5 * NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4251,20 +4302,29 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
itBase->second.currentState.getValues()[0].mValue.long_value);
+ // Value for dimension, state key {{}, ON GROUP}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(screenOnGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Bucket status after screen state change ON->VR.
// Both ON and VR are in the same state group, so the base should not change.
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10,
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_VR);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4274,20 +4334,29 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, ON GROUP}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(screenOnGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Bucket status after screen state change VR->ON.
// Both ON and VR are in the same state group, so the base should not change.
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12,
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 12 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_ON);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4297,19 +4366,28 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, ON GROUP}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(screenOnGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 5 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Bucket status after screen state change VR->OFF.
- screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15,
+ screenEvent = CreateScreenStateChangedEvent(bucketStartTimeNs + 15 * NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
StateManager::getInstance().onLogEvent(*screenEvent);
- ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {}
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4319,13 +4397,22 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(screenOffGroup.group_id(),
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, OFF GROUP}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(screenOffGroup.group_id(),
+ it->first.getStateValuesKey().getValues()[0].mValue.long_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 15 * NS_PER_SEC);
// Value for dimension, state key {{}, ON GROUP}
+ it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(screenOnGroup.group_id(),
it->first.getStateValuesKey().getValues()[0].mValue.long_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(16, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 15 * NS_PER_SEC);
// Value for dimension, state key {{}, kStateUnknown}
it++;
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4334,37 +4421,46 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 5 * NS_PER_SEC,
+ bucketStartTimeNs + 5 * NS_PER_SEC);
// Start dump report and check output.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 50, true /* include recent buckets */, true,
- NO_TIME_CONSTRAINTS, &strSet, &output);
+ valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
ASSERT_EQ(3, report.value_metrics().data_size());
+ // {{}, kStateUnknown}
auto data = report.value_metrics().data(0);
ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+ EXPECT_EQ(5 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {{}, ON GROUP}
data = report.value_metrics().data(1);
ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(16, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOnGroup.group_id(), data.slice_by_state(0).group_id());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {{}, OFF GROUP}
data = report.value_metrics().data(2);
ASSERT_EQ(1, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(9, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_group_id());
EXPECT_EQ(screenOffGroup.group_id(), data.slice_by_state(0).group_id());
+ EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
}
/*
@@ -4386,6 +4482,35 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
auto fieldsInState = stateLink->mutable_fields_in_state();
*fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+ /*
+ NOTE: "1" denotes uid 1 and "2" denotes uid 2.
+ bucket # 1 bucket # 2
+ 10 20 30 40 50 60 70 80 90 100 110 120 (seconds)
+ |------------------------------------------|---------------------------------|--
+
+ (kStateUnknown)
+ 1
+ |-------------|
+ 20
+
+ 2
+ |----------------------------|
+ 40
+
+ (FOREGROUND)
+ 1 1
+ |----------------------------|-------------| |------|
+ 40 20 10
+
+
+ (BACKGROUND)
+ 1
+ |------------|
+ 20
+ 2
+ |-------------|---------------------------------|
+ 20 50
+ */
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
// ValueMetricProducer initialized.
@@ -4400,64 +4525,64 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
// Uid 1 process state change from kStateUnknown -> Foreground
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
data->clear();
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 1 /*uid*/, 6));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+ 1 /*uid*/, 6));
// This event should be skipped.
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 2 /*uid*/, 8));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+ 2 /*uid*/, 8));
return true;
}))
// Uid 2 process state change from kStateUnknown -> Background
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40);
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
data->clear();
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40, 2 /*uid*/, 9));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+ 2 /*uid*/, 9));
// This event should be skipped.
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40, 1 /*uid*/, 12));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+ 1 /*uid*/, 12));
return true;
}))
// Uid 1 process state change from Foreground -> Background
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20);
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 20 * NS_PER_SEC);
data->clear();
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20, 1 /*uid*/, 13));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
+ 1 /*uid*/, 13));
// This event should be skipped.
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20, 2 /*uid*/, 11));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 20 * NS_PER_SEC,
+ 2 /*uid*/, 11));
return true;
}))
// Uid 1 process state change from Background -> Foreground
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40);
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 40 * NS_PER_SEC);
data->clear();
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40, 1 /*uid*/, 17));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
+ 1 /*uid*/, 17));
// This event should be skipped.
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40, 2 /*uid */, 15));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 40 * NS_PER_SEC,
+ 2 /*uid */, 15));
return true;
}))
// Dump report pull.
.WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
vector<std::shared_ptr<LogEvent>>* data) {
- EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50);
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
data->clear();
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50, 2 /*uid*/, 20));
- data->push_back(
- CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50, 1 /*uid*/, 21));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
+ 2 /*uid*/, 20));
+ data->push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 50 * NS_PER_SEC,
+ 1 /*uid*/, 21));
return true;
}));
@@ -4489,6 +4614,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
// Base for dimension key {uid 2}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4505,12 +4631,14 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
// Bucket status after uid 1 process state change kStateUnknown -> Foreground.
- auto uidProcessEvent = CreateUidProcessStateChangedEvent(
- bucketStartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ auto uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
// Base for dimension key {uid 1}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4528,8 +4656,18 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+ // Value for key {uid 1, FOREGROUND}.
+ it++;
+ ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
- // Base for dimension key {uid 2}
+ // Base for dimension key {uid 2}.
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
@@ -4538,22 +4676,42 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
itBase->second.currentState.getValues()[0].mValue.int_value);
- // Value for key {uid 2, kStateUnknown}
+ // Value for key {uid 2, kStateUnknown}.
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
- EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
// Bucket status after uid 2 process state change kStateUnknown -> Background.
- uidProcessEvent = CreateUidProcessStateChangedEvent(
- bucketStartTimeNs + 40, 2 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucketStartTimeNs + 40 * NS_PER_SEC, 2 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
- // Base for dimension key {uid 1}.
+ ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {uid 2}.
it = valueProducer->mCurrentSlicedBucket.begin();
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
+ EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {uid 2, BACKGROUND}.
+ ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Base for dimension key {uid 1}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
EXPECT_EQ(6, itBase->second.baseInfos[0].base.long_value);
EXPECT_TRUE(itBase->second.hasCurrentState);
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
@@ -4563,26 +4721,33 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
- EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
- // Base for dimension key {uid 2}
+ // Value for key {uid 1, FOREGROUND}.
it++;
- itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
- EXPECT_TRUE(itBase->second.baseInfos[0].hasBase);
- EXPECT_EQ(9, itBase->second.baseInfos[0].base.long_value);
- EXPECT_TRUE(itBase->second.hasCurrentState);
- ASSERT_EQ(1, itBase->second.currentState.getValues().size());
- EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
- itBase->second.currentState.getValues()[0].mValue.int_value);
+ ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
// Value for key {uid 2, kStateUnknown}
+ it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
- EXPECT_EQ(-1, it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 40 * NS_PER_SEC,
+ bucketStartTimeNs + 40 * NS_PER_SEC);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4612,6 +4777,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
// Base for dimension key {uid 1}
it++;
@@ -4629,6 +4796,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+ EXPECT_EQ(20 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4638,6 +4807,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4647,13 +4818,16 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* kStateTracker::kUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
+ EXPECT_EQ(40 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
// Bucket status after uid 1 process state change from Foreground -> Background.
- uidProcessEvent = CreateUidProcessStateChangedEvent(
- bucket2StartTimeNs + 20, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
- ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
ASSERT_EQ(4UL, valueProducer->mPastBuckets.size());
ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
// Base for dimension key {uid 2}.
@@ -4672,6 +4846,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
// Base for dimension key {uid 1}
it++;
itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
@@ -4688,6 +4864,17 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {uid 1, BACKGROUND}
+ it++;
+ ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 20 * NS_PER_SEC);
+
// Value for key {uid 1, FOREGROUND}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4697,6 +4884,9 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucket2StartTimeNs + 20 * NS_PER_SEC);
+
// Value for key {uid 2, kStateUnknown}
it++;
ASSERT_EQ(1, it->first.getDimensionKeyInWhat().getValues().size());
@@ -4705,10 +4895,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
// Bucket status after uid 1 process state change Background->Foreground.
- uidProcessEvent = CreateUidProcessStateChangedEvent(
- bucket2StartTimeNs + 40, 1 /* uid */, android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 40 * NS_PER_SEC, 1 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
StateManager::getInstance().onLogEvent(*uidProcessEvent);
ASSERT_EQ(5UL, valueProducer->mCurrentSlicedBucket.size());
@@ -4729,6 +4921,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
// Base for dimension key {uid 1}
it++;
@@ -4746,6 +4939,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
// Value for key {uid 1, BACKGROUND}
it++;
@@ -4756,6 +4950,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucket2StartTimeNs + 40 * NS_PER_SEC);
// Value for key {uid 1, FOREGROUND}
it++;
@@ -4766,6 +4962,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(3, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+ bucket2StartTimeNs + 40 * NS_PER_SEC);
// Value for key {uid 2, kStateUnknown}
it++;
@@ -4774,17 +4972,20 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 40 * NS_PER_SEC);
// Start dump report and check output.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucket2StartTimeNs + 50, true /* include recent buckets */, true,
- NO_TIME_CONSTRAINTS, &strSet, &output);
+ valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
ASSERT_EQ(5, report.value_metrics().data_size());
+ // {uid 1, BACKGROUND}
auto data = report.value_metrics().data(0);
ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(4, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
@@ -4792,14 +4993,18 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
data.slice_by_state(0).value());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {uid 2, kStateUnknown}
data = report.value_metrics().data(1);
ASSERT_EQ(1, report.value_metrics().data(1).bucket_info_size());
EXPECT_EQ(2, report.value_metrics().data(1).bucket_info(0).values(0).value_long());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+ EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {uid 1, FOREGROUND}
data = report.value_metrics().data(2);
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -4808,14 +5013,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(2, report.value_metrics().data(2).bucket_info_size());
EXPECT_EQ(4, report.value_metrics().data(2).bucket_info(0).values(0).value_long());
EXPECT_EQ(7, report.value_metrics().data(2).bucket_info(1).values(0).value_long());
+ EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+ // {uid 1, kStateUnknown}
data = report.value_metrics().data(3);
ASSERT_EQ(1, report.value_metrics().data(3).bucket_info_size());
EXPECT_EQ(3, report.value_metrics().data(3).bucket_info(0).values(0).value_long());
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(-1 /*StateTracker::kStateUnknown*/, data.slice_by_state(0).value());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ // {uid 2, BACKGROUND}
data = report.value_metrics().data(4);
EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
EXPECT_TRUE(data.slice_by_state(0).has_value());
@@ -4824,6 +5034,1630 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
ASSERT_EQ(2, report.value_metrics().data(4).bucket_info_size());
EXPECT_EQ(6, report.value_metrics().data(4).bucket_info(0).values(0).value_long());
EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state when data is not
+ * present in pulled data during a state change.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataInStateChange) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric =
+ ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ /*
+ NOTE: "-" means that the data was not present in the pulled data.
+
+ bucket # 1
+ 10 20 30 40 50 60 (seconds)
+ |-------------------------------------------------------|--
+ x (kStateUnknown)
+ |-----------|
+ 10
+
+ x x (ON)
+ |---------------------| |-----------|
+ 20 10
+
+ - (OFF)
+ */
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // ValueMetricProducer initialized.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }))
+ // Battery saver mode state changed to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
+ return true;
+ }))
+ // Battery saver mode state changed to OFF but data for dimension key {} is not present
+ // in the pulled data.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
+ data->clear();
+ return true;
+ }))
+ // Battery saver mode state changed to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC, 7));
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+ valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+ util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+ // Bucket status after metric initialized.
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension key {}
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
+
+ // Bucket status after battery saver mode ON event.
+ unique_ptr<LogEvent> batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+ // Base for dimension key {}
+
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Bucket status after battery saver mode OFF event which is not present
+ // in the pulled data.
+ unique_ptr<LogEvent> batterySaverOffEvent =
+ CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
+
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_FALSE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Bucket status after battery saver mode ON event.
+ batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 40 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(2, report.value_metrics().data_size());
+
+ // {{}, kStateUnknown}
+ ValueMetricData data = report.value_metrics().data(0);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+ // {{}, ON}
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test for metric that slices by state when data is not present in pulled data
+ * during an event and then a flush occurs for the current bucket. With the new
+ * condition timer behavior, a "new" MetricDimensionKey is inserted into
+ * `mCurrentSlicedBucket` before intervals are closed/added to that new
+ * MetricDimensionKey.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMissingDataThenFlushBucket) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric =
+ ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ /*
+ NOTE: "-" means that the data was not present in the pulled data.
+
+ bucket # 1
+ 10 20 30 40 50 60 (seconds)
+ |-------------------------------------------------------|--
+ - (kStateUnknown)
+
+ - (ON)
+ */
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // ValueMetricProducer initialized but data for dimension key {} is not present
+ // in the pulled data..
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ return true;
+ }))
+ // Battery saver mode state changed to ON but data for dimension key {} is not present
+ // in the pulled data.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 15));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+ valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+ util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+ // Bucket status after metric initialized.
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
+
+ // Bucket status after battery saver mode ON event which is not present
+ // in the pulled data.
+ unique_ptr<LogEvent> batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+ ASSERT_EQ(0UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+}
+
+TEST(ValueMetricProducerTest, TestSlicedStateWithNoPullOnBucketBoundary) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric =
+ ValueMetricProducerTestHelper::createMetricWithState("BATTERY_SAVER_MODE_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ /*
+ bucket # 1 bucket # 2
+ 10 20 30 40 50 60 70 80 90 100 110 120 (seconds)
+ |------------------------------------|---------------------------|--
+ x (kStateUnknown)
+ |-----|
+ 10
+ x x (ON)
+ |-----| |-----------|
+ 10 20
+ x (OFF)
+ |------------------------|
+ 40
+ */
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // ValueMetricProducer initialized.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 3));
+ return true;
+ }))
+ // Battery saver mode state changed to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 5));
+ return true;
+ }))
+ // Battery saver mode state changed to OFF.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 7));
+ return true;
+ }))
+ // Battery saver mode state changed to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 10));
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 15));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithState(
+ pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {});
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+ valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+ util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+ // Bucket status after metric initialized.
+ ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for dimension, state key {{}, kStateUnknown}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs);
+
+ // Bucket status after battery saver mode ON event.
+ unique_ptr<LogEvent> batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Bucket status after battery saver mode OFF event.
+ unique_ptr<LogEvent> batterySaverOffEvent =
+ CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 20 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOffEvent);
+
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, OFF}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{}, ON}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Bucket status after battery saver mode ON event.
+ batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucket2StartTimeNs + 30 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, OFF}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
+ bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{}, ON}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(3, report.value_metrics().data_size());
+
+ // {{}, kStateUnknown}
+ ValueMetricData data = report.value_metrics().data(0);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+ // {{}, ON}
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+ // {{}, OFF}
+ data = report.value_metrics().data(2);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state when data is not
+ * present in pulled data during a condition change.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithDataMissingInConditionChange) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState(
+ "BATTERY_SAVER_MODE_STATE");
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ /*
+ NOTE: "-" means that the data was not present in the pulled data.
+
+ bucket # 1
+ 10 20 30 40 50 60 (seconds)
+ |-------------------------------------------------------|--
+
+ T F T (Condition)
+ x (ON)
+ |----------------------| -
+ 20
+ */
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // Battery saver mode state changed to ON.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC, 3));
+ return true;
+ }))
+ // Condition changed to false.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC);
+ data->clear();
+ data->push_back(
+ CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5));
+ return true;
+ }))
+ // Condition changed to true but data for dimension key {} is not present in the
+ // pulled data.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+ data->clear();
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 50 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(
+ tagId, bucketStartTimeNs + 50 * NS_PER_SEC, 20));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
+ pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {},
+ ConditionState::kTrue);
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED,
+ valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(
+ util::BATTERY_SAVER_MODE_STATE_CHANGED));
+
+ // Bucket status after battery saver mode ON event.
+ unique_ptr<LogEvent> batterySaverOnEvent =
+ CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC);
+ StateManager::getInstance().onLogEvent(*batterySaverOnEvent);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket status after condition change to false.
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 30 * NS_PER_SEC);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_TRUE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket status after condition change to true.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 40 * NS_PER_SEC);
+ // Base for dimension key {}
+ ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_FALSE(itBase->second.hasCurrentState);
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, ON}
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucketStartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(1, report.value_metrics().data_size());
+
+ // {{}, ON}
+ ValueMetricData data = report.value_metrics().data(0);
+ EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+}
+
+/*
+ * Test slicing condition_true_nanos by state for metric that slices by state with a primary field,
+ * condition, and has multiple dimensions.
+ */
+TEST(ValueMetricProducerTest, TestSlicedStateWithMultipleDimensions) {
+ // Set up ValueMetricProducer.
+ ValueMetric metric =
+ ValueMetricProducerTestHelper::createMetricWithConditionAndState("UID_PROCESS_STATE");
+ metric.mutable_dimensions_in_what()->set_field(tagId);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+ metric.mutable_dimensions_in_what()->add_child()->set_field(3);
+
+ MetricStateLink* stateLink = metric.add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(tagId, {1 /* uid */});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
+
+ /*
+ bucket # 1 bucket # 2
+ 10 20 30 40 50 60 70 80 90 100 110 120 (seconds)
+ |------------------------------------------|---------------------------------|--
+
+ T F T (Condition)
+ (FOREGROUND)
+ x {1, 14}
+ |------|
+ 10
+
+ x {1, 16}
+ |------|
+ 10
+ x {2, 8}
+ |-------------|
+ 20
+
+ (BACKGROUND)
+ x {1, 14}
+ |-------------| |----------|---------------------------------|
+ 20 15 50
+
+ x {1, 16}
+ |-------------| |----------|---------------------------------|
+ 20 15 50
+
+ x {2, 8}
+ |----------| |----------|-------------------|
+ 15 15 30
+ */
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ // Uid 1 process state change from kStateUnknown -> Foreground
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 10 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+ 1 /*uid*/, 3, 14 /*tag*/));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+ 1 /*uid*/, 3, 16 /*tag*/));
+
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 10 * NS_PER_SEC,
+ 2 /*uid*/, 5, 8 /*tag*/));
+ return true;
+ }))
+ // Uid 1 process state change from Foreground -> Background
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+ 1 /*uid*/, 5, 14 /*tag*/));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+ 1 /*uid*/, 5, 16 /*tag*/));
+
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC,
+ 2 /*uid*/, 7, 8 /*tag*/));
+
+ return true;
+ }))
+ // Uid 2 process state change from kStateUnknown -> Background
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 25 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+ 2 /*uid*/, 9, 8 /*tag*/));
+
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+ 1 /*uid*/, 9, 14 /* tag */));
+
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 25 * NS_PER_SEC,
+ 1 /*uid*/, 9, 16 /* tag */));
+
+ return true;
+ }))
+ // Condition changed to false.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 40 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+ 1 /*uid*/, 11, 14 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+ 1 /*uid*/, 11, 16 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 40 * NS_PER_SEC,
+ 2 /*uid*/, 11, 8 /*tag*/));
+
+ return true;
+ }))
+ // Condition changed to true.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 45 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+ 1 /*uid*/, 13, 14 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+ 1 /*uid*/, 13, 16 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(tagId, bucketStartTimeNs + 45 * NS_PER_SEC,
+ 2 /*uid*/, 13, 8 /*tag*/));
+ return true;
+ }))
+ // Uid 2 process state change from Background -> Foreground
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 30 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /*uid*/, 18, 8 /*tag*/));
+
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 14 /* tag */));
+ // This event should be skipped.
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/, 18, 16 /* tag */));
+
+ return true;
+ }))
+ // Dump report pull.
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 50 * NS_PER_SEC);
+ data->clear();
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 14 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 1 /*uid*/, 21, 16 /* tag */));
+ data->push_back(CreateThreeValueLogEvent(
+ tagId, bucket2StartTimeNs + 50 * NS_PER_SEC, 2 /*uid*/, 21, 8 /*tag*/));
+ return true;
+ }));
+
+ StateManager::getInstance().clear();
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithConditionAndState(
+ pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {}, ConditionState::kTrue);
+ EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size());
+
+ // Set up StateManager and check that StateTrackers are initialized.
+ StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer);
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Condition is true.
+ // Bucket status after uid 1 process state change kStateUnknown -> Foreground.
+ auto uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucketStartTimeNs + 10 * NS_PER_SEC, 1 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+ ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(4UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension {uid 1, tag 16}.
+ auto it = valueProducer->mCurrentSlicedBucket.begin();
+ auto itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 10 * NS_PER_SEC);
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket status after uid 1 process state change Foreground -> Background.
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+ ASSERT_EQ(2UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(6UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension {uid 1, tag 16}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket status after uid 2 process state change kStateUnknown -> Background.
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucketStartTimeNs + 25 * NS_PER_SEC, 2 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_BACKGROUND);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+ ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension {uid 2, tag 8}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 2, uid 8}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 25 * NS_PER_SEC);
+
+ // Value for key {{uid 2, uid 8}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension {uid 1, tag 16}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket 1 status after condition change to false.
+ // All condition timers should be turned off.
+ valueProducer->onConditionChanged(false, bucketStartTimeNs + 40 * NS_PER_SEC);
+ ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension {uid 2, tag 8}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 2, uid 8}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 15 * NS_PER_SEC,
+ bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Value for key {{uid 2, uid 8}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension {uid 1, tag 16}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 40 * NS_PER_SEC);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket 1 status after condition change to true.
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 45 * NS_PER_SEC);
+ ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+ ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+ // Base for dimension {uid 2, tag 8}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 2, uid 8}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 15 * NS_PER_SEC,
+ bucketStartTimeNs + 45 * NS_PER_SEC);
+
+ // Value for key {{uid 2, uid 8}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension {uid 1, tag 16}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 45 * NS_PER_SEC);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 20 * NS_PER_SEC,
+ bucketStartTimeNs + 45 * NS_PER_SEC);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Pull at end of first bucket.
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(
+ CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 14 /* tag */));
+ allData.push_back(
+ CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 1 /*uid*/, 13, 16 /* tag */));
+ allData.push_back(
+ CreateThreeValueLogEvent(tagId, bucket2StartTimeNs, 2 /*uid*/, 13, 8 /*tag*/));
+ valueProducer->onDataPulled(allData, /** succeeds */ true, bucket2StartTimeNs + 1);
+
+ // Buckets flushed after end of first bucket.
+ // All condition timers' behavior should rollover to bucket 2.
+ ASSERT_EQ(8UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(5UL, valueProducer->mPastBuckets.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+ // Base for dimension {uid 2, tag 8}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 2, uid 8}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+ EXPECT_EQ(30 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+ // Value for key {{uid 2, uid 8}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension {uid 1, tag 16}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+ EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+ EXPECT_EQ(35 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+ ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+ EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+ ASSERT_EQ(1, valueProducer->mPastBuckets[it->first].size());
+ EXPECT_EQ(10 * NS_PER_SEC, valueProducer->mPastBuckets[it->first][0].mConditionTrueNs);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Bucket 2 status after uid 2 process state change Background->Foreground.
+ uidProcessEvent =
+ CreateUidProcessStateChangedEvent(bucket2StartTimeNs + 30 * NS_PER_SEC, 2 /* uid */,
+ android::app::PROCESS_STATE_IMPORTANT_FOREGROUND);
+ StateManager::getInstance().onLogEvent(*uidProcessEvent);
+
+ ASSERT_EQ(9UL, valueProducer->mCurrentSlicedBucket.size());
+ ASSERT_EQ(3UL, valueProducer->mCurrentBaseInfo.size());
+ // Base for dimension {uid 2, tag 8}.
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 2, uid 8}, FOREGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{uid 2, uid 8}, BACKGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 30 * NS_PER_SEC,
+ bucket2StartTimeNs + 30 * NS_PER_SEC);
+
+ // Value for key {{uid 2, uid 8}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(8, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Base for dimension {uid 1, tag 16}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, uid 16}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
+ // Base for dimension key {uid 1, tag 14}.
+ it++;
+ itBase = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat());
+ ASSERT_EQ(1, itBase->second.currentState.getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{uid 1, tag 14}, BACKGROUND}.
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+
+ // Value for key {{uid 1, uid 16}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 16}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(16, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Value for key {{uid 1, tag 14}, FOREGROUND}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+
+ // Value for key {{uid 1, tag 14}, kStateUnknown}.
+ it++;
+ ASSERT_EQ(2, it->first.getDimensionKeyInWhat().getValues().size());
+ EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+ EXPECT_EQ(14, it->first.getDimensionKeyInWhat().getValues()[1].mValue.int_value);
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
+
+ // Start dump report and check output.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC,
+ true /* include recent buckets */, true, NO_TIME_CONSTRAINTS,
+ &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(6, report.value_metrics().data_size());
+
+ // {{uid 1, tag 14}, FOREGROUND}.
+ auto data = report.value_metrics().data(0);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+ // {{uid 1, tag 16}, BACKGROUND}.
+ data = report.value_metrics().data(1);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+ // {{uid 1, tag 14}, BACKGROUND}.
+ data = report.value_metrics().data(2);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
+
+ // {{uid 1, tag 16}, FOREGROUND}.
+ data = report.value_metrics().data(3);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+ // {{uid 2, tag 8}, FOREGROUND}.
+ data = report.value_metrics().data(4);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+
+ // {{uid 2, tag 8}, BACKGROUND}.
+ data = report.value_metrics().data(5);
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
}
TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
@@ -4894,15 +6728,23 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
itBase->second.currentState.getValues()[0].mValue.int_value);
- // Value for key {{}, -1}
- ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+ // Value for key {{}, ON}
+ ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
std::unordered_map<MetricDimensionKey, ValueMetricProducer::CurrentValueBucket>::iterator it =
valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 20 * NS_PER_SEC);
+ // Value for key {{}, -1}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(-1 /*StateTracker::kUnknown*/,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
// Bucket status after battery saver mode OFF event.
unique_ptr<LogEvent> batterySaverOffEvent =
@@ -4917,15 +6759,27 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
itBase->second.currentState.getValues()[0].mValue.int_value);
- // Value for key {{}, ON}
- ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+ // Value for key {{}, OFF}
+ ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size());
it = valueProducer->mCurrentSlicedBucket.begin();
EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::OFF,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+ // Value for key {{}, ON}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::ON,
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(2, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucketStartTimeNs + 30 * NS_PER_SEC);
+ // Value for key {{}, -1}
+ it++;
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
// Pull at end of first bucket.
vector<shared_ptr<LogEvent>> allData;
@@ -4944,6 +6798,15 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(1, itBase->second.currentState.getValues().size());
EXPECT_EQ(BatterySaverModeStateChanged::OFF,
itBase->second.currentState.getValues()[0].mValue.int_value);
+ // Value for key {{}, OFF}
+ it = valueProducer->mCurrentSlicedBucket.begin();
+ assertConditionTimer(it->second.conditionTimer, true, 0, bucket2StartTimeNs);
+ // Value for key {{}, ON}
+ it++;
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+ // Value for key {{}, -1}
+ it++;
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
// Bucket 2 status after condition change to false.
valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC);
@@ -4964,6 +6827,19 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
it->first.getStateValuesKey().getValues()[0].mValue.int_value);
EXPECT_TRUE(it->second.intervals[0].hasValue);
EXPECT_EQ(4, it->second.intervals[0].value.long_value);
+ assertConditionTimer(it->second.conditionTimer, false, 10 * NS_PER_SEC,
+ bucket2StartTimeNs + 10 * NS_PER_SEC);
+ // Value for key {{}, ON}
+ it++;
+ EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size());
+ ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size());
+ EXPECT_EQ(BatterySaverModeStateChanged::ON,
+ it->first.getStateValuesKey().getValues()[0].mValue.int_value);
+ EXPECT_FALSE(it->second.intervals[0].hasValue);
+ assertConditionTimer(it->second.conditionTimer, false, 0, bucketStartTimeNs + 30 * NS_PER_SEC);
+ // Value for key {{}, -1}
+ it++;
+ assertConditionTimer(it->second.conditionTimer, false, 0, 0);
// Start dump report and check output.
ProtoOutputStream output;
@@ -4982,6 +6858,7 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value());
ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, data.bucket_info(0).values(0).value_long());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
data = report.value_metrics().data(1);
EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id());
@@ -4990,6 +6867,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) {
ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(6, data.bucket_info(0).values(0).value_long());
EXPECT_EQ(4, data.bucket_info(1).values(0).value_long());
+ EXPECT_EQ(30 * NS_PER_SEC, data.bucket_info(0).condition_true_nanos());
+ EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(1).condition_true_nanos());
}
/*
diff --git a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
index 076000fab80f..65e5875e39bf 100644
--- a/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
+++ b/cmds/statsd/tests/metrics/parsing_utils/config_update_utils_test.cpp
@@ -920,14 +920,13 @@ TEST_F(ConfigUpdateTest, TestEventMetricPreserve) {
// Create an initial config.
EXPECT_TRUE(initConfig(config));
- set<int64_t> replacedMatchers;
- set<int64_t> replacedConditions;
unordered_map<int64_t, int> metricToActivationMap;
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_PRESERVE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+ metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_PRESERVE);
}
TEST_F(ConfigUpdateTest, TestEventMetricActivationAdded) {
@@ -957,14 +956,13 @@ TEST_F(ConfigUpdateTest, TestEventMetricActivationAdded) {
eventActivation->set_atom_matcher_id(startMatcher.id());
eventActivation->set_ttl_seconds(5);
- set<int64_t> replacedMatchers;
- set<int64_t> replacedConditions;
unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_REPLACE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(config, oldMetricProducerMap, oldMetricProducers,
+ metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricWhatChanged) {
@@ -987,14 +985,13 @@ TEST_F(ConfigUpdateTest, TestEventMetricWhatChanged) {
// Create an initial config.
EXPECT_TRUE(initConfig(config));
- set<int64_t> replacedMatchers = {whatMatcher.id()};
- set<int64_t> replacedConditions;
unordered_map<int64_t, int> metricToActivationMap;
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_REPLACE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {whatMatcher.id()}, /*replacedConditions=*/{},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricConditionChanged) {
@@ -1017,14 +1014,13 @@ TEST_F(ConfigUpdateTest, TestEventMetricConditionChanged) {
// Create an initial config.
EXPECT_TRUE(initConfig(config));
- set<int64_t> replacedMatchers;
- set<int64_t> replacedConditions = {predicate.id()};
unordered_map<int64_t, int> metricToActivationMap;
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_REPLACE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{predicate.id()},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestMetricConditionLinkDepsChanged) {
@@ -1054,14 +1050,13 @@ TEST_F(ConfigUpdateTest, TestMetricConditionLinkDepsChanged) {
// Create an initial config.
EXPECT_TRUE(initConfig(config));
- set<int64_t> replacedMatchers;
- set<int64_t> replacedConditions = {linkPredicate.id()};
unordered_map<int64_t, int> metricToActivationMap;
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_REPLACE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {}, /*replacedConditions=*/{linkPredicate.id()},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestEventMetricActivationDepsChange) {
@@ -1090,14 +1085,13 @@ TEST_F(ConfigUpdateTest, TestEventMetricActivationDepsChange) {
// Create an initial config.
EXPECT_TRUE(initConfig(config));
- set<int64_t> replacedMatchers = {startMatcher.id()}; // The activation matcher is replaced.
- set<int64_t> replacedConditions;
unordered_map<int64_t, int> metricToActivationMap = {{12345, 0}};
- UpdateStatus status = UPDATE_UNKNOWN;
- EXPECT_TRUE(determineEventMetricUpdateStatus(config, *metric, oldMetricProducerMap,
- oldMetricProducers, metricToActivationMap,
- replacedMatchers, replacedConditions, status));
- EXPECT_EQ(status, UPDATE_REPLACE);
+ vector<UpdateStatus> metricsToUpdate(1, UPDATE_UNKNOWN);
+ EXPECT_TRUE(determineAllMetricUpdateStatuses(
+ config, oldMetricProducerMap, oldMetricProducers, metricToActivationMap,
+ /*replacedMatchers*/ {startMatcher.id()}, /*replacedConditions=*/{},
+ /*replacedStates=*/{}, metricsToUpdate));
+ EXPECT_EQ(metricsToUpdate[0], UPDATE_REPLACE);
}
TEST_F(ConfigUpdateTest, TestUpdateEventMetrics) {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index a2d0b892aa0a..1f8cf8ac6d1d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -46,39 +46,20 @@ public abstract class ActivityManagerInternal {
// Access modes for handleIncomingUser.
- /**
- * Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
- */
public static final int ALLOW_NON_FULL = 0;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
- * or {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in the same profile
- * group.
+ * if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_NON_FULL_IN_PROFILE_OR_FULL = 1;
- /**
- * Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
- * only.
- */
+ public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
public static final int ALLOW_FULL_ONLY = 2;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
- * or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in the same profile group.
+ * or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL = 3;
- /**
- * Requires {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}, or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in same profile group,
- * otherwise {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. (so this is an extension
- * to {@link #ALLOW_NON_FULL})
- */
- public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL = 4;
+ public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
/**
* Verify that calling app has access to the given provider.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 04f72f6dc71d..167b5a8029c0 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -6741,14 +6741,10 @@ public class AppOpsManager {
*/
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(int code, int uid, @Mode int mode) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
mService.setUidMode(code, uid, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -6766,7 +6762,11 @@ public class AppOpsManager {
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setUidMode(@NonNull String appOp, int uid, @Mode int mode) {
- setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
+ try {
+ mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** @hide */
@@ -6795,14 +6795,10 @@ public class AppOpsManager {
@TestApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(int code, int uid, String packageName, @Mode int mode) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
mService.setMode(code, uid, packageName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -6822,7 +6818,11 @@ public class AppOpsManager {
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(@NonNull String op, int uid, @Nullable String packageName,
@Mode int mode) {
- setMode(strOpToOp(op), uid, packageName, mode);
+ try {
+ mService.setMode(strOpToOp(op), uid, packageName, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
@@ -7298,14 +7298,10 @@ public class AppOpsManager {
* @hide
*/
public int unsafeCheckOpRawNoThrow(int op, int uid, @NonNull String packageName) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
return mService.checkOperationRaw(op, uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -7477,20 +7473,8 @@ public class AppOpsManager {
}
}
- int mode;
- // Making the binder call "noteOperation" usually sets Binder.callingUid to the calling
- // processes UID. Hence clearing the calling UID is superfluous.
- // If the call is inside the system server though "noteOperation" is not a binder all,
- // it is only a method call. Hence Binder.callingUid might still be set to the app that
- // called the system server. This can lead to problems as not every app can see the
- // same appops the system server can see.
- long token = Binder.clearCallingIdentity();
- try {
- mode = mService.noteOperation(op, uid, packageName, attributionTag,
- collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ int mode = mService.noteOperation(op, uid, packageName, attributionTag,
+ collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
@@ -7653,17 +7637,10 @@ public class AppOpsManager {
}
}
- int mode;
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
- try {
- mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
- proxiedAttributionTag, myUid, mContext.getOpPackageName(),
- mContext.getAttributionTag(), collectionMode == COLLECT_ASYNC, message,
- shouldCollectMessage);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
+ proxiedAttributionTag, myUid, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), collectionMode == COLLECT_ASYNC, message,
+ shouldCollectMessage);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
@@ -7713,8 +7690,6 @@ public class AppOpsManager {
*/
@UnsupportedAppUsage
public int checkOp(int op, int uid, String packageName) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
int mode = mService.checkOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
@@ -7723,8 +7698,6 @@ public class AppOpsManager {
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -7735,15 +7708,11 @@ public class AppOpsManager {
*/
@UnsupportedAppUsage
public int checkOpNoThrow(int op, int uid, String packageName) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
int mode = mService.checkOperation(op, uid, packageName);
return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -7995,16 +7964,9 @@ public class AppOpsManager {
}
}
- int mode;
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
- try {
- mode = mService.startOperation(getClientId(), op, uid, packageName,
- attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC,
- message, shouldCollectMessage);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ int mode = mService.startOperation(getClientId(), op, uid, packageName,
+ attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message,
+ shouldCollectMessage);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
@@ -8067,14 +8029,10 @@ public class AppOpsManager {
*/
public void finishOp(int op, int uid, @NonNull String packageName,
@Nullable String attributionTag) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
mService.finishOperation(getClientId(), op, uid, packageName, attributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -8666,14 +8624,10 @@ public class AppOpsManager {
// TODO: Uncomment below annotation once b/73559440 is fixed
// @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true)
public boolean isOperationActive(int code, int uid, String packageName) {
- // Clear calling UID to handle calls from inside the system server. See #noteOpNoThrow
- long token = Binder.clearCallingIdentity();
try {
return mService.isOperationActive(code, uid, packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cd352e141994..fbc87ce0cace 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -19,12 +19,16 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -35,6 +39,7 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.ArraySet;
+import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.os.IResultReceiver;
@@ -102,11 +107,20 @@ import java.lang.annotation.RetentionPolicy;
* FLAG_ONE_SHOT, <b>both</b> FLAG_ONE_SHOT and FLAG_NO_CREATE need to be supplied.
*/
public final class PendingIntent implements Parcelable {
+ private static final String TAG = "PendingIntent";
private final IIntentSender mTarget;
private IResultReceiver mCancelReceiver;
private IBinder mWhitelistToken;
private ArraySet<CancelListener> mCancelListeners;
+ /**
+ * It is now required to specify either {@link #FLAG_IMMUTABLE}
+ * or {@link #FLAG_MUTABLE} when creating a PendingIntent.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.R)
+ static final long PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED = 160794467L;
+
/** @hide */
@IntDef(flag = true,
value = {
@@ -115,6 +129,7 @@ public final class PendingIntent implements Parcelable {
FLAG_CANCEL_CURRENT,
FLAG_UPDATE_CURRENT,
FLAG_IMMUTABLE,
+ FLAG_MUTABLE,
Intent.FILL_IN_ACTION,
Intent.FILL_IN_DATA,
@@ -175,6 +190,20 @@ public final class PendingIntent implements Parcelable {
public static final int FLAG_IMMUTABLE = 1<<26;
/**
+ * Flag indicating that the created PendingIntent should be mutable.
+ * This flag cannot be combined with {@link #FLAG_IMMUTABLE}. <p>Up until
+ * {@link android.os.Build.VERSION_CODES#R}, PendingIntents are assumed to
+ * be mutable by default, unless {@link #FLAG_IMMUTABLE} is set. Starting
+ * with {@link android.os.Build.VERSION_CODES#S}, it will be required to
+ * explicitly specify the mutability of PendingIntents on creation with
+ * either (@link #FLAG_IMMUTABLE} or {@link #FLAG_MUTABLE}. It is strongly
+ * recommended to use {@link #FLAG_IMMUTABLE} when creating a
+ * PendingIntent. {@link #FLAG_MUTABLE} should only be used when some
+ * functionality relies on modifying the underlying intent.
+ */
+ public static final int FLAG_MUTABLE = 1<<25;
+
+ /**
* Exception thrown when trying to send through a PendingIntent that
* has been canceled or is otherwise no longer able to execute the request.
*/
@@ -286,6 +315,23 @@ public final class PendingIntent implements Parcelable {
sOnMarshaledListener.set(listener);
}
+ private static void checkFlags(int flags, String packageName) {
+ final boolean flagImmutableSet = (flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+ final boolean flagMutableSet = (flags & PendingIntent.FLAG_MUTABLE) != 0;
+
+ if (flagImmutableSet && flagMutableSet) {
+ throw new IllegalArgumentException(
+ "Cannot set both FLAG_IMMUTABLE and FLAG_MUTABLE for PendingIntent");
+ }
+
+ if (Compatibility.isChangeEnabled(PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED)
+ && !flagImmutableSet && !flagMutableSet) {
+ Log.wtf(TAG, packageName + ": Targeting S+ (version " + Build.VERSION_CODES.S
+ + " and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE"
+ + " be specified when creating a PendingIntent");
+ }
+ }
+
/**
* Retrieve a PendingIntent that will start a new activity, like calling
* {@link Context#startActivity(Intent) Context.startActivity(Intent)}.
@@ -350,6 +396,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -376,6 +423,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
@@ -495,6 +543,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
+ checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -521,6 +570,7 @@ public final class PendingIntent implements Parcelable {
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
+ checkFlags(flags, packageName);
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -572,6 +622,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
@@ -651,6 +702,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
+ checkFlags(flags, packageName);
try {
intent.prepareToLeaveProcess(context);
IIntentSender target =
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
index e07bc0215a6b..a52fc891790c 100644
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ b/core/java/android/bluetooth/BluetoothCodecConfig.java
@@ -51,19 +51,25 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface SourceCodecType {}
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_SBC = 0;
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_AAC = 1;
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_APTX = 2;
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_LDAC = 4;
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_MAX = 5;
-
+ @UnsupportedAppUsage
public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
/** @hide */
@@ -75,10 +81,13 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface CodecPriority {}
+ @UnsupportedAppUsage
public static final int CODEC_PRIORITY_DISABLED = -1;
+ @UnsupportedAppUsage
public static final int CODEC_PRIORITY_DEFAULT = 0;
+ @UnsupportedAppUsage
public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
@@ -95,18 +104,25 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface SampleRate {}
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_NONE = 0;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_44100 = 0x1 << 0;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_48000 = 0x1 << 1;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_88200 = 0x1 << 2;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_96000 = 0x1 << 3;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_176400 = 0x1 << 4;
+ @UnsupportedAppUsage
public static final int SAMPLE_RATE_192000 = 0x1 << 5;
@@ -120,12 +136,16 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface BitsPerSample {}
+ @UnsupportedAppUsage
public static final int BITS_PER_SAMPLE_NONE = 0;
+ @UnsupportedAppUsage
public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
+ @UnsupportedAppUsage
public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
+ @UnsupportedAppUsage
public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
@@ -138,10 +158,13 @@ public final class BluetoothCodecConfig implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface ChannelMode {}
+ @UnsupportedAppUsage
public static final int CHANNEL_MODE_NONE = 0;
+ @UnsupportedAppUsage
public static final int CHANNEL_MODE_MONO = 0x1 << 0;
+ @UnsupportedAppUsage
public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
private final @SourceCodecType int mCodecType;
@@ -154,6 +177,7 @@ public final class BluetoothCodecConfig implements Parcelable {
private final long mCodecSpecific3;
private final long mCodecSpecific4;
+ @UnsupportedAppUsage
public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
@SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
@ChannelMode int channelMode, long codecSpecific1,
@@ -170,6 +194,7 @@ public final class BluetoothCodecConfig implements Parcelable {
mCodecSpecific4 = codecSpecific4;
}
+ @UnsupportedAppUsage
public BluetoothCodecConfig(@SourceCodecType int codecType) {
mCodecType = codecType;
mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
@@ -391,6 +416,7 @@ public final class BluetoothCodecConfig implements Parcelable {
*
* @return the codec type
*/
+ @UnsupportedAppUsage
public @SourceCodecType int getCodecType() {
return mCodecType;
}
@@ -411,6 +437,7 @@ public final class BluetoothCodecConfig implements Parcelable {
*
* @return the codec priority
*/
+ @UnsupportedAppUsage
public @CodecPriority int getCodecPriority() {
return mCodecPriority;
}
@@ -441,6 +468,7 @@ public final class BluetoothCodecConfig implements Parcelable {
*
* @return the codec sample rate
*/
+ @UnsupportedAppUsage
public @SampleRate int getSampleRate() {
return mSampleRate;
}
@@ -455,6 +483,7 @@ public final class BluetoothCodecConfig implements Parcelable {
*
* @return the codec bits per sample
*/
+ @UnsupportedAppUsage
public @BitsPerSample int getBitsPerSample() {
return mBitsPerSample;
}
@@ -479,6 +508,7 @@ public final class BluetoothCodecConfig implements Parcelable {
*
* @return a codec specific value1.
*/
+ @UnsupportedAppUsage
public long getCodecSpecific1() {
return mCodecSpecific1;
}
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
index 1e394b830d51..7b567b4098e7 100644
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ b/core/java/android/bluetooth/BluetoothCodecStatus.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,6 +39,7 @@ public final class BluetoothCodecStatus implements Parcelable {
* This extra represents the current codec status of the A2DP
* profile.
*/
+ @UnsupportedAppUsage
public static final String EXTRA_CODEC_STATUS =
"android.bluetooth.extra.CODEC_STATUS";
@@ -196,6 +198,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return the current codec configuration
*/
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig getCodecConfig() {
return mCodecConfig;
}
@@ -205,6 +208,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return an array with the codecs local capabilities
*/
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig[] getCodecsLocalCapabilities() {
return mCodecsLocalCapabilities;
}
@@ -214,6 +218,7 @@ public final class BluetoothCodecStatus implements Parcelable {
*
* @return an array with the codecs selectable capabilities
*/
+ @UnsupportedAppUsage
public @Nullable BluetoothCodecConfig[] getCodecsSelectableCapabilities() {
return mCodecsSelectableCapabilities;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5452f92c929f..005648ffec36 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -351,6 +351,13 @@ public abstract class Context {
* due to its foreground state such as an activity or foreground service, then this flag will
* allow the bound app to get the same capabilities, as long as it has the required permissions
* as well.
+ *
+ * If binding from a top app and its target SDK version is at or above
+ * {@link android.os.Build.VERSION_CODES#R}, the app needs to
+ * explicitly use BIND_INCLUDE_CAPABILITIES flag to pass all capabilities to the service so the
+ * other app can have while-use-use access such as location, camera, microphone from background.
+ * If binding from a top app and its target SDK version is below
+ * {@link android.os.Build.VERSION_CODES#R}, BIND_INCLUDE_CAPABILITIES is implicit.
*/
public static final int BIND_INCLUDE_CAPABILITIES = 0x000001000;
@@ -3179,8 +3186,8 @@ public abstract class Context {
* {@link #BIND_AUTO_CREATE}, {@link #BIND_DEBUG_UNBIND},
* {@link #BIND_NOT_FOREGROUND}, {@link #BIND_ABOVE_CLIENT},
* {@link #BIND_ALLOW_OOM_MANAGEMENT}, {@link #BIND_WAIVE_PRIORITY}.
- * {@link #BIND_IMPORTANT}, or
- * {@link #BIND_ADJUST_WITH_ACTIVITY}.
+ * {@link #BIND_IMPORTANT}, {@link #BIND_ADJUST_WITH_ACTIVITY},
+ * {@link #BIND_NOT_PERCEPTIBLE}, or {@link #BIND_INCLUDE_CAPABILITIES}.
* @return {@code true} if the system is in the process of bringing up a
* service that your client has permission to bind to; {@code false}
* if the system couldn't find the service or if your client doesn't
@@ -3201,6 +3208,8 @@ public abstract class Context {
* @see #BIND_WAIVE_PRIORITY
* @see #BIND_IMPORTANT
* @see #BIND_ADJUST_WITH_ACTIVITY
+ * @see #BIND_NOT_PERCEPTIBLE
+ * @see #BIND_INCLUDE_CAPABILITIES
*/
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index da56abf73516..a9f143987cd4 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1878,6 +1878,7 @@ public class PackageInstaller {
/** {@hide} */
@SystemApi
+ @TestApi
public void setInstallAsInstantApp(boolean isInstantApp) {
if (isInstantApp) {
installFlags |= PackageManager.INSTALL_INSTANT_APP;
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 8f99edf61ece..dda1890b0757 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -941,6 +941,7 @@ public final class DisplayManager {
*/
String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default";
+ // TODO(b/162536543): rename it once it is proved not harmful for users.
/**
* Key for controlling which packages are explicitly blocked from running at refresh rates
* higher than 60hz. An app may be added to this list if they exhibit performance issues at
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index c4d123ca4382..06b5b6745bd1 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -32,10 +32,12 @@ import android.media.soundtrigger_middleware.RecognitionMode;
import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
+import android.os.ParcelFileDescriptor;
import android.os.SharedMemory;
import android.system.ErrnoException;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.UUID;
@@ -109,7 +111,12 @@ class ConversionUtil {
aidlModel.type = apiModel.getType();
aidlModel.uuid = api2aidlUuid(apiModel.getUuid());
aidlModel.vendorUuid = api2aidlUuid(apiModel.getVendorUuid());
- aidlModel.data = byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel");
+ try {
+ aidlModel.data = ParcelFileDescriptor.dup(
+ byteArrayToSharedMemory(apiModel.getData(), "SoundTrigger SoundModel"));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
aidlModel.dataSize = apiModel.getData().length;
return aidlModel;
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index b15109e67086..d80a7e794220 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -34,7 +34,6 @@ import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.permission.SplitPermissionInfoParcelable;
-import android.os.Binder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -544,15 +543,10 @@ public final class PermissionManager {
+ permission);
return PackageManager.PERMISSION_DENIED;
}
- // Clear Binder.callingUid in case this is called inside the system server. See
- // more extensive comment in checkPackageNamePermissionUncached
- long token = Binder.clearCallingIdentity();
try {
return am.checkPermission(permission, pid, uid);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
@@ -685,20 +679,11 @@ public final class PermissionManager {
/* @hide */
private static int checkPackageNamePermissionUncached(
String permName, String pkgName, @UserIdInt int userId) {
- // Makeing the binder call "checkPermission" usually sets Binder.callingUid to the calling
- // processes UID. Hence clearing the calling UID is superflous.
- // If the call is inside the system server though "checkPermission" is not a binder all, it
- // is only a method call. Hence Binder.callingUid might still be set to the app that called
- // the system server. This can lead to problems as not every app can check the same
- // permissions the system server can check.
- long token = Binder.clearCallingIdentity();
try {
return ActivityThread.getPermissionManager().checkPermission(
permName, pkgName, userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
- } finally {
- Binder.restoreCallingIdentity(token);
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8a5963ed02eb..a7055ec0f050 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7954,6 +7954,12 @@ public final class Settings {
public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on";
/**
+ * The last computed night mode bool the last time the phone was on
+ * @hide
+ */
+ public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed";
+
+ /**
* The current night mode that has been overridden to turn off by the system. Owned
* and controlled by UiModeManagerService. Constants are as per
* UiModeManager.
@@ -9078,6 +9084,22 @@ public final class Settings {
};
/**
+ * How long Assistant handles have enabled in milliseconds.
+ *
+ * @hide
+ */
+ public static final String ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS =
+ "reminder_exp_learning_time_elapsed";
+
+ /**
+ * How many times the Assistant has been triggered using the touch gesture.
+ *
+ * @hide
+ */
+ public static final String ASSIST_HANDLES_LEARNING_EVENT_COUNT =
+ "reminder_exp_learning_event_count";
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
*/
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 5a74ec0e52c0..b77265b0ebf6 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -144,6 +144,17 @@ public class IntArray implements Cloneable {
}
/**
+ * Adds the values in the specified array to this array.
+ */
+ public void addAll(int[] values) {
+ final int count = values.length;
+ ensureCapacity(count);
+
+ System.arraycopy(values, 0, mValues, mSize, count);
+ mSize += count;
+ }
+
+ /**
* Ensures capacity to append at least <code>count</code> values.
*/
private void ensureCapacity(int count) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d55c25fc1a4f..c698b926e233 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -316,11 +316,19 @@ public final class SurfaceControl implements Parcelable {
public static final int HIDDEN = 0x00000004;
/**
- * Surface creation flag: The surface contains secure content, special
- * measures will be taken to disallow the surface's content to be copied
- * from another process. In particular, screenshots and VNC servers will
- * be disabled, but other measures can take place, for instance the
- * surface might not be hardware accelerated.
+ * Surface creation flag: Skip this layer and its children when taking a screenshot. This
+ * also includes mirroring and screen recording, so the layers with flag SKIP_SCREENSHOT
+ * will not be included on non primary displays.
+ * @hide
+ */
+ public static final int SKIP_SCREENSHOT = 0x00000040;
+
+ /**
+ * Surface creation flag: Special measures will be taken to disallow the surface's content to
+ * be copied. In particular, screenshots and secondary, non-secure displays will render black
+ * content instead of the surface content.
+ *
+ * @see #createDisplay(String, boolean)
* @hide
*/
public static final int SECURE = 0x00000080;
@@ -482,15 +490,6 @@ public final class SurfaceControl implements Parcelable {
public static final int POWER_MODE_ON_SUSPEND = 4;
/**
- * A value for windowType used to indicate that the window should be omitted from screenshots
- * and display mirroring. A temporary workaround until we express such things with
- * the hierarchy.
- * TODO: b/64227542
- * @hide
- */
- public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731;
-
- /**
* internal representation of how to interpret pixel value, used only to convert to ColorSpace.
*/
private static final int INTERNAL_DATASPACE_SRGB = 142671872;
@@ -3287,6 +3286,22 @@ public final class SurfaceControl implements Parcelable {
return this;
}
+ /**
+ * Adds or removes the flag SKIP_SCREENSHOT of the surface. Setting the flag is equivalent
+ * to creating the Surface with the {@link #SKIP_SCREENSHOT} flag.
+ *
+ * @hide
+ */
+ public Transaction setSkipScreenshot(SurfaceControl sc, boolean skipScrenshot) {
+ checkPreconditions(sc);
+ if (skipScrenshot) {
+ nativeSetFlags(mNativeObject, sc.mNativeObject, SKIP_SCREENSHOT, SKIP_SCREENSHOT);
+ } else {
+ nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SKIP_SCREENSHOT);
+ }
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index dd1978ebb026..85dc2aea4b1c 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -24,11 +24,11 @@ import android.util.Log;
import android.view.FrameMetrics;
import android.view.ThreadedRenderer;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor.Session;
import com.android.internal.util.FrameworkStatsLog;
/**
+ * A class that allows the app to get the frame metrics from HardwareRendererObserver.
* @hide
*/
public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvailableListener {
@@ -45,28 +45,21 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
private long mBeginTime = UNKNOWN_TIMESTAMP;
private long mEndTime = UNKNOWN_TIMESTAMP;
private boolean mShouldTriggerTrace;
+ private boolean mSessionEnd;
private int mTotalFramesCount = 0;
private int mMissedFramesCount = 0;
private long mMaxFrameTimeNanos = 0;
private Session mSession;
- public FrameTracker(@NonNull Session session,
- @NonNull Handler handler, @NonNull ThreadedRenderer renderer) {
- mSession = session;
- mRendererWrapper = new ThreadedRendererWrapper(renderer);
- mMetricsWrapper = new FrameMetricsWrapper();
- mObserver = new HardwareRendererObserver(this, mMetricsWrapper.getTiming(), handler);
- }
-
/**
- * This constructor is only for unit tests.
+ * Constructor of FrameTracker.
* @param session a trace session.
- * @param renderer a test double for ThreadedRenderer
- * @param metrics a test double for FrameMetrics
+ * @param handler a handler for handling callbacks.
+ * @param renderer a ThreadedRendererWrapper instance.
+ * @param metrics a FrameMetricsWrapper instance.
*/
- @VisibleForTesting
- public FrameTracker(@NonNull Session session, Handler handler,
+ public FrameTracker(@NonNull Session session, @NonNull Handler handler,
@NonNull ThreadedRendererWrapper renderer, @NonNull FrameMetricsWrapper metrics) {
mSession = session;
mRendererWrapper = renderer;
@@ -77,15 +70,11 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
/**
* Begin a trace session of the CUJ.
*/
- public void begin() {
+ public synchronized void begin() {
long timestamp = System.nanoTime();
if (DEBUG) {
Log.d(TAG, "begin: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
- + ", end(ns)=" + mEndTime + ", session=" + mSession);
- }
- if (mBeginTime != UNKNOWN_TIMESTAMP && mEndTime == UNKNOWN_TIMESTAMP) {
- // We have an ongoing tracing already, skip subsequent calls.
- return;
+ + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
}
mBeginTime = timestamp;
mEndTime = UNKNOWN_TIMESTAMP;
@@ -96,32 +85,48 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
/**
* End the trace session of the CUJ.
*/
- public void end() {
+ public synchronized void end() {
long timestamp = System.nanoTime();
if (DEBUG) {
Log.d(TAG, "end: time(ns)=" + timestamp + ", begin(ns)=" + mBeginTime
- + ", end(ns)=" + mEndTime + ", session=" + mSession);
- }
- if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) {
- // We haven't started a trace yet.
- return;
+ + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
}
mEndTime = timestamp;
Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
+ // We don't remove observer here,
+ // will remove it when all the frame metrics in this duration are called back.
+ // See onFrameMetricsAvailable for the logic of removing the observer.
+ }
+
+ /**
+ * Cancel the trace session of the CUJ.
+ */
+ public synchronized void cancel() {
+ if (mBeginTime == UNKNOWN_TIMESTAMP || mEndTime != UNKNOWN_TIMESTAMP) return;
+ if (DEBUG) {
+ Log.d(TAG, "cancel: time(ns)=" + System.nanoTime() + ", begin(ns)=" + mBeginTime
+ + ", end(ns)=" + mEndTime + ", session=" + mSession.getName());
+ }
+ Trace.endAsyncSection(mSession.getName(), (int) mBeginTime);
+ mRendererWrapper.removeObserver(mObserver);
+ mBeginTime = UNKNOWN_TIMESTAMP;
+ mEndTime = UNKNOWN_TIMESTAMP;
+ mShouldTriggerTrace = false;
}
@Override
- public void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
+ public synchronized void onFrameMetricsAvailable(int dropCountSinceLastInvocation) {
// Since this callback might come a little bit late after the end() call.
// We should keep tracking the begin / end timestamp.
// Then compare with vsync timestamp to check if the frame is in the duration of the CUJ.
- if (mBeginTime == UNKNOWN_TIMESTAMP) return; // We haven't started tracing yet.
long vsyncTimestamp = mMetricsWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP);
- if (vsyncTimestamp < mBeginTime) return; // The tracing has been started.
+ // Discard the frame metrics which is not in the trace session.
+ if (vsyncTimestamp < mBeginTime) return;
- // If the end time has not been set, we are still in the tracing.
- if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime) {
+ // We stop getting callback when the vsync is later than the end calls.
+ if (mEndTime != UNKNOWN_TIMESTAMP && vsyncTimestamp > mEndTime && !mSessionEnd) {
+ mSessionEnd = true;
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
mRendererWrapper.removeObserver(mObserver);
@@ -170,9 +175,8 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
/**
* Trigger the prefetto daemon.
*/
- @VisibleForTesting
public void triggerPerfetto() {
- InteractionJankMonitor.trigger();
+ InteractionJankMonitor.getInstance().trigger();
}
/**
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 5a0cbf9e93e4..19dc2ed6daea 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -21,15 +21,17 @@ import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_IN
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.HandlerThread;
-import android.view.ThreadedRenderer;
+import android.util.Log;
+import android.util.SparseArray;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.jank.FrameTracker.FrameMetricsWrapper;
+import com.android.internal.jank.FrameTracker.ThreadedRendererWrapper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* This class let users to begin and end the always on tracing mechanism.
@@ -38,11 +40,17 @@ import java.util.Map;
public class InteractionJankMonitor {
private static final String TAG = InteractionJankMonitor.class.getSimpleName();
private static final boolean DEBUG = false;
- private static final Object LOCK = new Object();
+ private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
+ private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
// Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
- public static final int CUJ_NOTIFICATION_SHADE_MOTION = 0;
- public static final int CUJ_NOTIFICATION_SHADE_GESTURE = 1;
+ public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 1;
+ public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_SCROLL_FLING = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_ROW_EXPAND = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = 0;
+ public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = 0;
private static final int NO_STATSD_LOGGING = -1;
@@ -53,141 +61,255 @@ public class InteractionJankMonitor {
UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__NOTIFICATION_SHADE_SWIPE,
};
- private static ThreadedRenderer sRenderer;
- private static Map<String, FrameTracker> sRunningTracker;
- private static HandlerThread sWorker;
- private static boolean sInitialized;
+ private static volatile InteractionJankMonitor sInstance;
+
+ private ThreadedRendererWrapper mRenderer;
+ private FrameMetricsWrapper mMetrics;
+ private SparseArray<FrameTracker> mRunningTrackers;
+ private SparseArray<Runnable> mTimeoutActions;
+ private HandlerThread mWorker;
+ private boolean mInitialized;
/** @hide */
@IntDef({
- CUJ_NOTIFICATION_SHADE_MOTION,
- CUJ_NOTIFICATION_SHADE_GESTURE
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
+ CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE_LOCK,
+ CUJ_NOTIFICATION_SHADE_SCROLL_FLING,
+ CUJ_NOTIFICATION_SHADE_ROW_EXPAND,
+ CUJ_NOTIFICATION_SHADE_ROW_SWIPE,
+ CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
+ CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE
})
@Retention(RetentionPolicy.SOURCE)
public @interface CujType {}
/**
- * @param view Any view in the view tree to get context and ThreadedRenderer.
+ * Get the singleton of InteractionJankMonitor.
+ * @return instance of InteractionJankMonitor
*/
- public static void init(@NonNull View view) {
- init(view, null, null, null);
+ public static InteractionJankMonitor getInstance() {
+ // Use DCL here since this method might be invoked very often.
+ if (sInstance == null) {
+ synchronized (InteractionJankMonitor.class) {
+ if (sInstance == null) {
+ sInstance = new InteractionJankMonitor(new HandlerThread(DEFAULT_WORKER_NAME));
+ }
+ }
+ }
+ return sInstance;
}
/**
- * Should be only invoked internally or from unit tests.
+ * This constructor should be only public to tests.
+ * @param worker the worker thread for the callbacks
*/
@VisibleForTesting
- public static void init(@NonNull View view, @NonNull ThreadedRenderer renderer,
- @NonNull Map<String, FrameTracker> map, @NonNull HandlerThread worker) {
+ public InteractionJankMonitor(@NonNull HandlerThread worker) {
+ mRunningTrackers = new SparseArray<>();
+ mTimeoutActions = new SparseArray<>();
+ mWorker = worker;
+ }
+
+ /**
+ * Init InteractionJankMonitor for later instrumentation.
+ * @param view Any view in the view tree to get context and ThreadedRenderer.
+ * @return boolean true if the instance has been initialized successfully.
+ */
+ public boolean init(@NonNull View view) {
//TODO (163505250): This should be no-op if not in droid food rom.
- synchronized (LOCK) {
- if (!sInitialized) {
- if (!view.isAttachedToWindow()) {
- throw new IllegalStateException("View is not attached!");
+ if (!mInitialized) {
+ synchronized (this) {
+ if (!mInitialized) {
+ if (!view.isAttachedToWindow()) {
+ Log.d(TAG, "Expect an attached view!", new Throwable());
+ return false;
+ }
+ mRenderer = new ThreadedRendererWrapper(view.getThreadedRenderer());
+ mMetrics = new FrameMetricsWrapper();
+ mWorker.start();
+ mInitialized = true;
}
- sRenderer = renderer == null ? view.getThreadedRenderer() : renderer;
- sRunningTracker = map == null ? new HashMap<>() : map;
- sWorker = worker == null ? new HandlerThread("Aot-Worker") : worker;
- sWorker.start();
- sInitialized = true;
}
}
+ return true;
}
/**
- * Must invoke init() before invoking this method.
+ * Create a {@link FrameTracker} instance.
+ * @param session the session associates with this tracker
+ * @return instance of the FrameTracker
*/
- public static void begin(@NonNull @CujType int cujType) {
- begin(cujType, null);
+ @VisibleForTesting
+ public FrameTracker createFrameTracker(Session session) {
+ synchronized (this) {
+ if (!mInitialized) return null;
+ return new FrameTracker(session, mWorker.getThreadHandler(), mRenderer, mMetrics);
+ }
}
/**
- * Should be only invoked internally or from unit tests.
+ * Begin a trace session, must invoke {@link #init(View)} before invoking this method.
+ * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+ * @return boolean true if the tracker is started successfully, false otherwise.
*/
- @VisibleForTesting
- public static void begin(@NonNull @CujType int cujType, FrameTracker tracker) {
+ public boolean begin(@CujType int cujType) {
//TODO (163505250): This should be no-op if not in droid food rom.
- //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
- synchronized (LOCK) {
- checkInitStateLocked();
- Session session = new Session(cujType);
- FrameTracker currentTracker = getTracker(session.getName());
- if (currentTracker != null) return;
- if (tracker == null) {
- tracker = new FrameTracker(session, sWorker.getThreadHandler(), sRenderer);
+ synchronized (this) {
+ return begin(cujType, 0L /* timeout */);
+ }
+ }
+
+ /**
+ * Begin a trace session, must invoke {@link #init(View)} before invoking this method.
+ * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+ * @param timeout the elapsed time in ms until firing the timeout action.
+ * @return boolean true if the tracker is started successfully, false otherwise.
+ */
+ public boolean begin(@CujType int cujType, long timeout) {
+ //TODO (163505250): This should be no-op if not in droid food rom.
+ synchronized (this) {
+ if (!mInitialized) {
+ Log.d(TAG, "Not initialized!", new Throwable());
+ return false;
}
- sRunningTracker.put(session.getName(), tracker);
+ Session session = new Session(cujType);
+ FrameTracker tracker = getTracker(session);
+ // Skip subsequent calls if we already have an ongoing tracing.
+ if (tracker != null) return false;
+
+ // begin a new trace session.
+ tracker = createFrameTracker(session);
+ mRunningTrackers.put(cujType, tracker);
tracker.begin();
+
+ // Cancel the trace if we don't get an end() call in specified duration.
+ timeout = timeout > 0L ? timeout : DEFAULT_TIMEOUT_MS;
+ Runnable timeoutAction = () -> cancel(cujType);
+ mTimeoutActions.put(cujType, timeoutAction);
+ mWorker.getThreadHandler().postDelayed(timeoutAction, timeout);
+ return true;
}
}
/**
- * Must invoke init() before invoking this method.
+ * End a trace session, must invoke {@link #init(View)} before invoking this method.
+ * @param cujType the specific {@link InteractionJankMonitor.CujType}.
+ * @return boolean true if the tracker is ended successfully, false otherwise.
*/
- public static void end(@NonNull @CujType int cujType) {
+ public boolean end(@CujType int cujType) {
//TODO (163505250): This should be no-op if not in droid food rom.
- //TODO (163510843): Remove synchronized, add @UiThread if only invoked from ui threads.
- synchronized (LOCK) {
- checkInitStateLocked();
+ synchronized (this) {
+ if (!mInitialized) {
+ Log.d(TAG, "Not initialized!", new Throwable());
+ return false;
+ }
+ // remove the timeout action first.
+ Runnable timeout = mTimeoutActions.get(cujType);
+ if (timeout != null) {
+ mWorker.getThreadHandler().removeCallbacks(timeout);
+ mTimeoutActions.remove(cujType);
+ }
+
Session session = new Session(cujType);
- FrameTracker tracker = getTracker(session.getName());
- if (tracker != null) {
- tracker.end();
- sRunningTracker.remove(session.getName());
+ FrameTracker tracker = getTracker(session);
+ // Skip this call since we haven't started a trace yet.
+ if (tracker == null) return false;
+ tracker.end();
+ mRunningTrackers.remove(session.getCuj());
+ return true;
+ }
+ }
+
+ /**
+ * Cancel the trace session, must invoke {@link #init(View)} before invoking this method.
+ * @return boolean true if the tracker is cancelled successfully, false otherwise.
+ */
+ public boolean cancel(@CujType int cujType) {
+ //TODO (163505250): This should be no-op if not in droid food rom.
+ synchronized (this) {
+ if (!mInitialized) {
+ Log.d(TAG, "Not initialized!", new Throwable());
+ return false;
}
+ // remove the timeout action first.
+ Runnable timeout = mTimeoutActions.get(cujType);
+ if (timeout != null) {
+ mWorker.getThreadHandler().removeCallbacks(timeout);
+ mTimeoutActions.remove(cujType);
+ }
+
+ Session session = new Session(cujType);
+ FrameTracker tracker = getTracker(session);
+ // Skip this call since we haven't started a trace yet.
+ if (tracker == null) return false;
+ tracker.cancel();
+ mRunningTrackers.remove(session.getCuj());
+ return true;
}
}
- private static void checkInitStateLocked() {
- if (!sInitialized) {
- throw new IllegalStateException("InteractionJankMonitor not initialized!");
+ private void destroy() {
+ synchronized (this) {
+ int trackers = mRunningTrackers.size();
+ for (int i = 0; i < trackers; i++) {
+ mRunningTrackers.valueAt(i).cancel();
+ }
+ mRunningTrackers = null;
+ mTimeoutActions.clear();
+ mTimeoutActions = null;
+ mWorker.quit();
+ mWorker = null;
}
}
/**
- * Should be only invoked from unit tests.
+ * Abandon current instance.
*/
@VisibleForTesting
- public static void reset() {
- sInitialized = false;
- sRenderer = null;
- sRunningTracker = null;
- if (sWorker != null) {
- sWorker.quit();
- sWorker = null;
+ public static void abandon() {
+ if (sInstance == null) return;
+ synchronized (InteractionJankMonitor.class) {
+ if (sInstance == null) return;
+ sInstance.destroy();
+ sInstance = null;
}
}
- private static FrameTracker getTracker(String sessionName) {
- synchronized (LOCK) {
- return sRunningTracker.get(sessionName);
+ private FrameTracker getTracker(Session session) {
+ synchronized (this) {
+ if (!mInitialized) return null;
+ return mRunningTrackers.get(session.getCuj());
}
}
/**
* Trigger the perfetto daemon to collect and upload data.
*/
- public static void trigger() {
- sWorker.getThreadHandler().post(
- () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+ @VisibleForTesting
+ public void trigger() {
+ synchronized (this) {
+ if (!mInitialized) return;
+ mWorker.getThreadHandler().post(
+ () -> PerfettoTrigger.trigger(PerfettoTrigger.TRIGGER_TYPE_JANK));
+ }
}
/**
* A class to represent a session.
*/
public static class Session {
- private @CujType int mId;
+ private @CujType int mCujType;
- public Session(@CujType int session) {
- mId = session;
+ public Session(@CujType int cujType) {
+ mCujType = cujType;
}
- public int getId() {
- return mId;
+ public int getCuj() {
+ return mCujType;
}
public int getStatsdInteractionType() {
- return CUJ_TO_STATSD_INTERACTION_TYPE[mId];
+ return CUJ_TO_STATSD_INTERACTION_TYPE[mCujType];
}
/** Describes whether the measurement from this session should be written to statsd. */
@@ -196,7 +318,7 @@ public class InteractionJankMonitor {
}
public String getName() {
- return "CujType<" + mId + ">";
+ return "Cuj<" + getCuj() + ">";
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e58990eff2c8..7516a879211f 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6613,22 +6613,29 @@ public class BatteryStatsImpl extends BatteryStats {
* the power consumption to the calling app.
*/
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
- noteBinderCallStats(workSourceUid, incrementalCallCount, callStats, binderThreadNativeTids,
+ Collection<BinderCallsStats.CallStat> callStats) {
+ noteBinderCallStats(workSourceUid, incrementalCallCount, callStats,
mClocks.elapsedRealtime(), mClocks.uptimeMillis());
}
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids,
+ Collection<BinderCallsStats.CallStat> callStats,
long elapsedRealtimeMs, long uptimeMs) {
synchronized (this) {
getUidStatsLocked(workSourceUid, elapsedRealtimeMs, uptimeMs)
.noteBinderCallStatsLocked(incrementalCallCount, callStats);
- mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
}
}
/**
+ * Takes note of native IDs of threads taking incoming binder calls. The CPU time
+ * of these threads is attributed to the apps making those binder calls.
+ */
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
+ }
+
+ /**
* Estimates the proportion of system server CPU activity handling incoming binder calls
* that can be attributed to each app
*/
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index f5bef0b006f5..70b1ad49d8b8 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -119,8 +119,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
if (uidEntry != null) {
ArrayMap<CallStatKey, CallStat> callStats = uidEntry.mCallStats;
mCallStatsObserver.noteCallStats(uidEntry.workSourceUid,
- uidEntry.incrementalCallCount, callStats.values(),
- mNativeTids.toArray());
+ uidEntry.incrementalCallCount, callStats.values()
+ );
uidEntry.incrementalCallCount = 0;
for (int j = callStats.size() - 1; j >= 0; j--) {
callStats.valueAt(j).incrementalCallCount = 0;
@@ -168,6 +168,7 @@ public class BinderCallsStats implements BinderInternal.Observer {
public void setCallStatsObserver(
BinderInternal.CallStatsObserver callStatsObserver) {
mCallStatsObserver = callStatsObserver;
+ noteBinderThreadNativeIds();
noteCallsStatsDelayed();
}
@@ -182,13 +183,13 @@ public class BinderCallsStats implements BinderInternal.Observer {
@Override
@Nullable
public CallSession callStarted(Binder binder, int code, int workSourceUid) {
+ noteNativeThreadId();
+
if (!mRecordingAllTransactionsForUid
&& (mDeviceState == null || mDeviceState.isCharging())) {
return null;
}
- noteNativeThreadId();
-
final CallSession s = obtainCallSession();
s.binderClass = binder.getClass();
s.transactionCode = code;
@@ -359,6 +360,16 @@ public class BinderCallsStats implements BinderInternal.Observer {
mNativeTids = copyOnWriteArray;
}
}
+
+ noteBinderThreadNativeIds();
+ }
+
+ private void noteBinderThreadNativeIds() {
+ if (mCallStatsObserver == null) {
+ return;
+ }
+
+ mCallStatsObserver.noteBinderThreadNativeIds(getNativeTids());
}
/**
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index 2645b8e84cf1..c14d8d805d29 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -143,8 +143,12 @@ public class BinderInternal {
* Notes incoming binder call stats associated with this work source UID.
*/
void noteCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats,
- int[] binderThreadNativeTids);
+ Collection<BinderCallsStats.CallStat> callStats);
+
+ /**
+ * Notes the native IDs of threads taking incoming binder calls.
+ */
+ void noteBinderThreadNativeIds(int[] binderThreadNativeTids);
}
/**
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index 1cdd42c7403e..3aa2390375ec 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -31,7 +31,7 @@ import java.util.Arrays;
*/
public class SystemServerCpuThreadReader {
private KernelCpuThreadReader mKernelCpuThreadReader;
- private int[] mBinderThreadNativeTids;
+ private int[] mBinderThreadNativeTids = new int[0]; // Sorted
private int[] mThreadCpuTimesUs;
private int[] mBinderThreadCpuTimesUs;
@@ -75,7 +75,8 @@ public class SystemServerCpuThreadReader {
}
public void setBinderThreadNativeTids(int[] nativeTids) {
- mBinderThreadNativeTids = nativeTids;
+ mBinderThreadNativeTids = nativeTids.clone();
+ Arrays.sort(mBinderThreadNativeTids);
}
/**
@@ -107,7 +108,8 @@ public class SystemServerCpuThreadReader {
int threadCpuUsagesSize = threadCpuUsages.size();
for (int j = 0; j < threadCpuUsagesSize; j++) {
KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
- boolean isBinderThread = isBinderThread(tcu.threadId);
+ boolean isBinderThread =
+ Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
for (int k = 0; k < len; k++) {
@@ -138,14 +140,4 @@ public class SystemServerCpuThreadReader {
return mDeltaCpuThreadTimes;
}
- private boolean isBinderThread(int threadId) {
- if (mBinderThreadNativeTids != null) {
- for (int i = 0; i < mBinderThreadNativeTids.length; i++) {
- if (threadId == mBinderThreadNativeTids[i]) {
- return true;
- }
- }
- }
- return false;
- }
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index 9f7436a13bdc..9874c6aabf04 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -72,7 +72,9 @@ public enum ProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM),
WM_DEBUG_WINDOW_ORGANIZER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
Consts.TAG_WM),
- TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+ WM_DEBUG_SYNC_ENGINE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
private volatile boolean mLogToProto;
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 5f590be72f52..e1a980caa635 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -120,6 +120,14 @@ message SecureSettingsProto {
}
optional Assist assist = 7;
+ message AssistHandles {
+ option (android.msg_privacy).dest = DEST_EXPLICIT;
+
+ optional SettingProto learning_time_elapsed_millis = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto learning_event_count = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+ optional AssistHandles assist_handles = 86;
+
message Autofill {
option (android.msg_privacy).dest = DEST_EXPLICIT;
@@ -617,5 +625,5 @@ message SecureSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 86;
+ // Next tag = 87;
}
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 03975daf1f76..25a9bbd8b445 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4374,7 +4374,7 @@
</string>
<!-- Dialog title for dialog shown when the multiple accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_multiple_service_warning_title">Turn on accessibility features?</string>
+ <string name="accessibility_shortcut_multiple_service_warning_title">Turn on shortcut for accessibility features?</string>
<!-- Message shown in dialog when user is in the process of enabling the multiple accessibility service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_multiple_service_warning">Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="service" example="TalkBack">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility.</string>
@@ -4383,7 +4383,7 @@
<string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
<!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
+ <string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g> shortcut?</string>
<!-- Message shown in dialog when user is in the process of enabling this accessibility service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_single_service_warning">Holding down both volume keys for a few seconds turns on <xliff:g id="service" example="TalkBack">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility.</string>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 6ae6faa5446e..71cb2acde94e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -228,15 +228,6 @@
</intent-filter>
</activity>
- <activity android:name="android.widget.focus.ListOfButtons"
- android:label="ListOfButtons"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
- </intent-filter>
- </activity>
-
<activity android:name="android.widget.focus.LinearLayoutGrid"
android:label="LinearLayoutGrid"
android:exported="true">
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java b/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
deleted file mode 100644
index 936c9999e7f8..000000000000
--- a/core/tests/coretests/src/android/widget/focus/ListOfEditTexts.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget.focus;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-
-import com.google.android.collect.Lists;
-
-import java.util.List;
-
-public class ListOfEditTexts extends Activity {
-
- private int mLinesPerEditText = 12;
-
- private ListView mListView;
- private LinearLayout mLinearLayout;
-
- public ListView getListView() {
- return mListView;
- }
-
- @Override
- protected void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- // create linear layout
- mLinearLayout = new LinearLayout(this);
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- // add a button above
- Button buttonAbove = new Button(this);
- buttonAbove.setLayoutParams(
- new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- buttonAbove.setText("button above list");
- mLinearLayout.addView(buttonAbove);
-
- // add a list view to it
- mListView = new ListView(this);
- mListView.setLayoutParams(new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- mListView.setDrawSelectorOnTop(false);
- mListView.setItemsCanFocus(true);
- mListView.setLayoutParams((new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- 0,
- 1f)));
-
- List<String> bodies = Lists.newArrayList(
- getBody("zero hello, my name is android"),
- getBody("one i'm a paranoid android"),
- getBody("two i robot. huh huh."),
- getBody("three not the g-phone!"));
-
- mListView.setAdapter(new MyAdapter(this, bodies));
- mLinearLayout.addView(mListView);
-
- // add button below
- Button buttonBelow = new Button(this);
- buttonBelow.setLayoutParams(
- new LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
- buttonBelow.setText("button below list");
- mLinearLayout.addView(buttonBelow);
-
- setContentView(mLinearLayout);
- }
-
- String getBody(String line) {
- StringBuilder sb = new StringBuilder((line.length() + 5) * mLinesPerEditText);
- for (int i = 0; i < mLinesPerEditText; i++) {
- sb.append(i + 1).append(' ').append(line);
- if (i < mLinesPerEditText - 1) {
- sb.append('\n'); // all but last line
- }
- }
- return sb.toString();
- }
-
-
- private static class MyAdapter extends ArrayAdapter<String> {
-
- public MyAdapter(Context context, List<String> bodies) {
- super(context, 0, bodies);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- String body = getItem(position);
-
- if (convertView != null) {
- ((EditText) convertView).setText(body);
- return convertView;
- }
-
- EditText editText = new EditText(getContext());
- editText.setText(body);
- return editText;
- }
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
index ece5037de15f..e17800f7b6fd 100644
--- a/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/FrameTrackerTest.java
@@ -16,7 +16,7 @@
package com.android.internal.jank;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.google.common.truth.Truth.assertThat;
@@ -75,20 +75,13 @@ public class FrameTrackerTest {
doNothing().when(mRenderer).addObserver(any());
doNothing().when(mRenderer).removeObserver(any());
- Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
- mTracker = Mockito.spy(new FrameTracker(session, handler, mRenderer, mWrapper));
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ mTracker = Mockito.spy(
+ new FrameTracker(session, handler, mRenderer, mWrapper));
doNothing().when(mTracker).triggerPerfetto();
}
@Test
- public void testIgnoresSecondBegin() {
- // Observer should be only added once in continuous calls.
- mTracker.begin();
- mTracker.begin();
- verify(mRenderer, only()).addObserver(any());
- }
-
- @Test
public void testOnlyFirstFrameOverThreshold() {
// Just provide current timestamp anytime mWrapper asked for VSYNC_TIMESTAMP
when(mWrapper.getMetric(FrameMetrics.VSYNC_TIMESTAMP))
@@ -170,6 +163,29 @@ public class FrameTrackerTest {
verify(mTracker).triggerPerfetto();
}
+ @Test
+ public void testBeginCancel() {
+ mTracker.begin();
+ verify(mRenderer).addObserver(any());
+
+ // First frame - not janky
+ setupFirstFrameMockWithDuration(4);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // normal frame - not janky
+ setupOtherFrameMockWithDuration(12);
+ mTracker.onFrameMetricsAvailable(0);
+
+ // a janky frame
+ setupOtherFrameMockWithDuration(30);
+ mTracker.onFrameMetricsAvailable(0);
+
+ mTracker.cancel();
+ verify(mRenderer).removeObserver(any());
+ // Since the tracker has been cancelled, shouldn't trigger perfetto.
+ verify(mTracker, never()).triggerPerfetto();
+ }
+
private void setupFirstFrameMockWithDuration(long durationMillis) {
doReturn(1L).when(mWrapper).getMetric(FrameMetrics.FIRST_DRAW_FRAME);
doReturn(TimeUnit.MILLISECONDS.toNanos(durationMillis))
diff --git a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
index 5c0b0c94f6d0..b669cc609baf 100644
--- a/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
+++ b/core/tests/coretests/src/com/android/internal/jank/InteractionJankMonitorTest.java
@@ -16,15 +16,20 @@
package com.android.internal.jank;
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_GESTURE;
+import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Message;
import android.view.View;
import android.view.ViewAttachTestActivity;
@@ -38,17 +43,13 @@ import com.android.internal.jank.InteractionJankMonitor.Session;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.mockito.Mockito;
-import org.testng.Assert;
-
-import java.util.HashMap;
-import java.util.Map;
+import org.mockito.ArgumentCaptor;
@SmallTest
public class InteractionJankMonitorTest {
private ViewAttachTestActivity mActivity;
private View mView;
- private FrameTracker mTracker;
+ private HandlerThread mWorker;
@Rule
public ActivityTestRule<ViewAttachTestActivity> mRule =
@@ -61,55 +62,52 @@ public class InteractionJankMonitorTest {
mView = mActivity.getWindow().getDecorView();
assertThat(mView.isAttachedToWindow()).isTrue();
- InteractionJankMonitor.reset();
+ InteractionJankMonitor.abandon();
- // Prepare a FrameTracker to inject.
- Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
- FrameMetricsWrapper wrapper = Mockito.spy(new FrameTracker.FrameMetricsWrapper());
- ThreadedRendererWrapper renderer =
- Mockito.spy(new ThreadedRendererWrapper(mView.getThreadedRenderer()));
- Handler handler = mActivity.getMainThreadHandler();
- mTracker = Mockito.spy(new FrameTracker(session, handler, renderer, wrapper));
+ Handler handler = spy(new Handler(mActivity.getMainLooper()));
+ doReturn(true).when(handler).sendMessageAtTime(any(), anyLong());
+ mWorker = spy(new HandlerThread("Interaction-jank-monitor-test"));
+ doNothing().when(mWorker).start();
+ doReturn(handler).when(mWorker).getThreadHandler();
}
@Test
public void testBeginEnd() {
- // Should throw exception if the view is not attached.
- Assert.assertThrows(IllegalStateException.class,
- () -> InteractionJankMonitor.init(new View(mActivity)));
+ // Should return false if the view is not attached.
+ InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
+ assertThat(monitor.init(new View(mActivity))).isFalse();
// Verify we init InteractionJankMonitor correctly.
- Map<String, FrameTracker> map = new HashMap<>();
- HandlerThread worker = Mockito.spy(new HandlerThread("Aot-test"));
- doNothing().when(worker).start();
- InteractionJankMonitor.init(mView, mView.getThreadedRenderer(), map, worker);
- verify(worker).start();
+ assertThat(monitor.init(mView)).isTrue();
+ verify(mWorker).start();
+
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
+ new ThreadedRendererWrapper(mView.getThreadedRenderer()),
+ new FrameMetricsWrapper()));
+ doReturn(tracker).when(monitor).createFrameTracker(any());
// Simulate a trace session and see if begin / end are invoked.
- Session session = new Session(CUJ_NOTIFICATION_SHADE_GESTURE);
- assertThat(map.get(session.getName())).isNull();
- InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE, mTracker);
- verify(mTracker).begin();
- assertThat(map.get(session.getName())).isEqualTo(mTracker);
- InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
- verify(mTracker).end();
- assertThat(map.get(session.getName())).isNull();
+ assertThat(monitor.begin(session.getCuj())).isTrue();
+ verify(tracker).begin();
+ assertThat(monitor.end(session.getCuj())).isTrue();
+ verify(tracker).end();
}
@Test
public void testCheckInitState() {
- // Should throw exception if invoking begin / end without init invocation.
- Assert.assertThrows(IllegalStateException.class,
- () -> InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE));
- Assert.assertThrows(IllegalStateException.class,
- () -> InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE));
+ InteractionJankMonitor monitor = new InteractionJankMonitor(mWorker);
+
+ // Should return false if invoking begin / end without init invocation.
+ assertThat(monitor.begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
+ assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isFalse();
// Everything should be fine if invoking init first.
boolean thrown = false;
try {
- InteractionJankMonitor.init(mActivity.getWindow().getDecorView());
- InteractionJankMonitor.begin(CUJ_NOTIFICATION_SHADE_GESTURE);
- InteractionJankMonitor.end(CUJ_NOTIFICATION_SHADE_GESTURE);
+ monitor.init(mView);
+ assertThat(monitor.begin(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
+ assertThat(monitor.end(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE)).isTrue();
} catch (Exception ex) {
thrown = true;
} finally {
@@ -117,4 +115,27 @@ public class InteractionJankMonitorTest {
}
}
+ @Test
+ public void testBeginCancel() {
+ InteractionJankMonitor monitor = spy(new InteractionJankMonitor(mWorker));
+
+ ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
+ assertThat(monitor.init(mView)).isTrue();
+
+ Session session = new Session(CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+ FrameTracker tracker = spy(new FrameTracker(session, mWorker.getThreadHandler(),
+ new ThreadedRendererWrapper(mView.getThreadedRenderer()),
+ new FrameMetricsWrapper()));
+ doReturn(tracker).when(monitor).createFrameTracker(any());
+
+ assertThat(monitor.begin(session.getCuj())).isTrue();
+ verify(tracker).begin();
+ verify(mWorker.getThreadHandler()).sendMessageAtTime(captor.capture(), anyLong());
+ Runnable runnable = captor.getValue().getCallback();
+ assertThat(runnable).isNotNull();
+ mWorker.getThreadHandler().removeCallbacks(runnable);
+ runnable.run();
+ verify(tracker).cancel();
+ }
+
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
index 22c41f3c9622..85f9c97629e3 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
@@ -60,7 +60,7 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
stat1.cpuTimeMicros = 1000;
callStats.add(stat1);
- bi.noteBinderCallStats(workSourceUid, 42, callStats, null);
+ bi.noteBinderCallStats(workSourceUid, 42, callStats);
callStats.clear();
BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
@@ -70,7 +70,7 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
stat2.cpuTimeMicros = 500;
callStats.add(stat2);
- bi.noteBinderCallStats(workSourceUid, 8, callStats, null);
+ bi.noteBinderCallStats(workSourceUid, 8, callStats);
BatteryStatsImpl.Uid uid = bi.getUidStatsLocked(workSourceUid);
assertEquals(42 + 8, uid.getBinderCallCount());
@@ -112,7 +112,7 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
stat1b.cpuTimeMicros = 1500;
callStats.add(stat1b);
- bi.noteBinderCallStats(workSourceUid1, 65, callStats, null);
+ bi.noteBinderCallStats(workSourceUid1, 65, callStats);
// No recorded stats for some methods. Must use the global average.
callStats.clear();
@@ -121,11 +121,11 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
stat2.incrementalCallCount = 10;
callStats.add(stat2);
- bi.noteBinderCallStats(workSourceUid2, 40, callStats, null);
+ bi.noteBinderCallStats(workSourceUid2, 40, callStats);
// No stats for any calls. Must use the global average
callStats.clear();
- bi.noteBinderCallStats(workSourceUid3, 50, callStats, null);
+ bi.noteBinderCallStats(workSourceUid3, 50, callStats);
bi.updateSystemServiceCallStats();
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index 96250db4aa51..0eb34a993dec 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -47,8 +47,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Random;
+import java.util.Set;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -770,13 +772,27 @@ public class BinderCallsStatsTest {
bcs.setSamplingInterval(1);
bcs.setTrackScreenInteractive(false);
+
final ArrayList<BinderCallsStats.CallStat> callStatsList = new ArrayList<>();
- bcs.setCallStatsObserver(
- (workSourceUid, incrementalCallCount, callStats, binderThreadIds) ->
- callStatsList.addAll(callStats));
+ final Set<Integer> nativeTids = new HashSet<>();
+ bcs.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
+ @Override
+ public void noteCallStats(int workSourceUid, long incrementalCallCount,
+ Collection<BinderCallsStats.CallStat> callStats) {
+ callStatsList.addAll(callStats);
+ }
+
+ @Override
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ for (int tid : binderThreadNativeTids) {
+ nativeTids.add(tid);
+ }
+ }
+ });
Binder binder = new Binder();
+ bcs.nativeTid = 1000;
CallSession callSession = bcs.callStarted(binder, 1, WORKSOURCE_UID);
bcs.time += 10;
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
@@ -785,6 +801,7 @@ public class BinderCallsStatsTest {
bcs.time += 20;
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
+ bcs.nativeTid = 2000;
callSession = bcs.callStarted(binder, 2, WORKSOURCE_UID);
bcs.time += 30;
bcs.callEnded(callSession, REQUEST_SIZE, REPLY_SIZE, WORKSOURCE_UID);
@@ -809,6 +826,10 @@ public class BinderCallsStatsTest {
assertEquals(30, callStats.maxCpuTimeMicros);
}
}
+
+ assertEquals(2, nativeTids.size());
+ assertTrue(nativeTids.contains(1000));
+ assertTrue(nativeTids.contains(2000));
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index ac5443e1c7ce..2eee140b921f 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -87,7 +87,7 @@ public class SystemServicePowerCalculatorTest {
stat1.cpuTimeMicros = 1000000;
callStats.add(stat1);
- mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats, null);
+ mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats);
callStats.clear();
BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
@@ -97,7 +97,7 @@ public class SystemServicePowerCalculatorTest {
stat2.cpuTimeMicros = 9000000;
callStats.add(stat2);
- mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats, null);
+ mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats);
mMockBatteryStats.updateSystemServiceCallStats();
mMockBatteryStats.updateSystemServerThreadStats();
diff --git a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
index 55d186c292f6..469a4ccd05e4 100644
--- a/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
@@ -16,16 +16,17 @@
package com.android.internal.util;
-import com.android.internal.util.CharSequences;
import static com.android.internal.util.CharSequences.forAsciiBytes;
-import junit.framework.TestCase;
+
import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
public class CharSequencesTest extends TestCase {
@SmallTest
public void testCharSequences() {
- String s = "Crazy Bob";
+ String s = "Hello Bob";
byte[] bytes = s.getBytes();
String copy = toString(forAsciiBytes(bytes));
@@ -34,11 +35,11 @@ public class CharSequencesTest extends TestCase {
copy = toString(forAsciiBytes(bytes, 0, s.length()));
assertTrue(s.equals(copy));
- String crazy = toString(forAsciiBytes(bytes, 0, 5));
- assertTrue("Crazy".equals(crazy));
+ String hello = toString(forAsciiBytes(bytes, 0, 5));
+ assertTrue("Hello".equals(hello));
- String a = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3));
- assertTrue("a".equals(a));
+ String l = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3));
+ assertTrue("l".equals(l));
String empty = toString(forAsciiBytes(bytes, 0, 3).subSequence(3, 3));
assertTrue("".equals(empty));
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0a0681479278..dd8f40d586bc 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -153,8 +153,8 @@
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="media" />
+
<assign-permission name="android.permission.INTERNET" uid="media" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="shell" />
@@ -164,7 +164,6 @@
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
@@ -175,10 +174,8 @@
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
<assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="graphics" />
<assign-permission name="android.permission.DUMP" uid="incidentd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="incidentd" />
@@ -193,10 +190,8 @@
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="statsd" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="gpu_service" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="gpu_service" />
<split-permission name="android.permission.ACCESS_FINE_LOCATION">
<new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 6b80bb60ec67..86e7adf945b7 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -151,6 +151,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1910833551": {
+ "message": "SyncSet{%x:%d} Start for %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"-1895337367": {
"message": "Delete root task display=%d winMode=%d",
"level": "VERBOSE",
@@ -463,6 +469,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1387080937": {
+ "message": "SyncSet{%x:%d} Child ready, now ready=%b and waiting on %d transactions",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"-1364754753": {
"message": "Task vanished taskId=%d",
"level": "VERBOSE",
@@ -481,6 +493,12 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-1340783230": {
+ "message": "SyncSet{%x:%d} Added %s. now waiting on %d transactions",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"-1340540100": {
"message": "Creating SnapshotStartingData",
"level": "VERBOSE",
@@ -859,6 +877,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/DragState.java"
},
+ "-678300709": {
+ "message": "SyncSet{%x:%d} Trying to add %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"-668956537": {
"message": " THUMBNAIL %s: CREATE",
"level": "INFO",
@@ -1735,6 +1759,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
},
+ "590184240": {
+ "message": "- NOT adding to sync: visible=%b hasListener=%b",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/WindowContainer.java"
+ },
"594260577": {
"message": "createWallpaperAnimations()",
"level": "DEBUG",
@@ -2005,6 +2035,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "1000601037": {
+ "message": "SyncSet{%x:%d} Set ready",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"1001904964": {
"message": "***** BOOT TIMEOUT: forcing display enabled",
"level": "WARN",
@@ -2599,6 +2635,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "2001924866": {
+ "message": "SyncSet{%x:%d} Finished. Reporting %d containers to %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_SYNC_ENGINE",
+ "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+ },
"2016061474": {
"message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
"level": "VERBOSE",
@@ -2775,6 +2817,9 @@
"WM_DEBUG_SWITCH": {
"tag": "WindowManager"
},
+ "WM_DEBUG_SYNC_ENGINE": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
diff --git a/graphics/java/android/graphics/BlurShader.java b/graphics/java/android/graphics/BlurShader.java
index 779a89051060..3bc811983336 100644
--- a/graphics/java/android/graphics/BlurShader.java
+++ b/graphics/java/android/graphics/BlurShader.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.NonNull;
import android.annotation.Nullable;
/**
@@ -28,6 +29,7 @@ public final class BlurShader extends Shader {
private final float mRadiusX;
private final float mRadiusY;
private final Shader mInputShader;
+ private final TileMode mEdgeTreatment;
private long mNativeInputShader = 0;
@@ -35,22 +37,42 @@ public final class BlurShader extends Shader {
* Create a {@link BlurShader} that blurs the contents of the optional input shader
* with the specified radius along the x and y axis. If no input shader is provided
* then all drawing commands issued with a {@link android.graphics.Paint} that this
- * shader is installed in will be blurred
+ * shader is installed in will be blurred.
+ *
+ * This uses a default {@link TileMode#DECAL} for edge treatment
+ *
* @param radiusX Radius of blur along the X axis
* @param radiusY Radius of blur along the Y axis
* @param inputShader Input shader that provides the content to be blurred
*/
public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader) {
+ this(radiusX, radiusY, inputShader, TileMode.DECAL);
+ }
+
+ /**
+ * Create a {@link BlurShader} that blurs the contents of the optional input shader
+ * with the specified radius along the x and y axis. If no input shader is provided
+ * then all drawing commands issued with a {@link android.graphics.Paint} that this
+ * shader is installed in will be blurred
+ * @param radiusX Radius of blur along the X axis
+ * @param radiusY Radius of blur along the Y axis
+ * @param inputShader Input shader that provides the content to be blurred
+ * @param edgeTreatment Policy for how to blur content near edges of the blur shader
+ */
+ public BlurShader(float radiusX, float radiusY, @Nullable Shader inputShader,
+ @NonNull TileMode edgeTreatment) {
mRadiusX = radiusX;
mRadiusY = radiusY;
mInputShader = inputShader;
+ mEdgeTreatment = edgeTreatment;
}
/** @hide **/
@Override
protected long createNativeInstance(long nativeMatrix) {
mNativeInputShader = mInputShader != null ? mInputShader.getNativeInstance() : 0;
- return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader);
+ return nativeCreate(nativeMatrix, mRadiusX, mRadiusY, mNativeInputShader,
+ mEdgeTreatment.nativeInt);
}
/** @hide **/
@@ -61,5 +83,5 @@ public final class BlurShader extends Shader {
}
private static native long nativeCreate(long nativeMatrix, float radiusX, float radiusY,
- long inputShader);
+ long inputShader, int edgeTreatment);
}
diff --git a/graphics/java/android/graphics/ParcelableColorSpace.java b/graphics/java/android/graphics/ParcelableColorSpace.java
index f9033a53d7e6..d408ac3718ca 100644
--- a/graphics/java/android/graphics/ParcelableColorSpace.java
+++ b/graphics/java/android/graphics/ParcelableColorSpace.java
@@ -25,8 +25,6 @@ import android.os.Parcelable;
* A {@link Parcelable} {@link ColorSpace}. In order to enable parceling, the ColorSpace
* must be either a {@link ColorSpace.Named Named} ColorSpace or a {@link ColorSpace.Rgb} instance
* that has an ICC parametric transfer function as returned by {@link Rgb#getTransferParameters()}.
- * TODO: Make public
- * @hide
*/
public final class ParcelableColorSpace extends ColorSpace implements Parcelable {
private final ColorSpace mColorSpace;
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index 8154ebf1e508..d71ff1138b25 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -95,7 +95,11 @@ public class Shader {
* repeat the shader's image horizontally and vertically, alternating
* mirror images so that adjacent images always seam
*/
- MIRROR (2);
+ MIRROR(2),
+ /**
+ * Only draw within the original domain, return transparent-black everywhere else
+ */
+ DECAL(3);
TileMode(int nativeInt) {
this.nativeInt = nativeInt;
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index b6668fbe4872..da5965dab71a 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -93,4 +93,8 @@
<string name="one_handed_tutorial_title">Using one-handed mode</string>
<!-- One-Handed Tutorial description [CHAR LIMIT=NONE] -->
<string name="one_handed_tutorial_description">To exit, swipe up from the bottom of the screen or tap anywhere above the app</string>
+ <!-- Accessibility description for start one-handed mode [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_start_one_handed">Start one-handed mode</string>
+ <!-- Accessibility description for stop one-handed mode [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_stop_one_handed">Exit one-handed mode</string>
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
index b15b5154c2a4..7c0c738644b7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java
@@ -29,6 +29,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -50,12 +52,16 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
private final Rect mLastUpdatedBounds = new Rect();
private final WindowManager mWindowManager;
+ private final AccessibilityManager mAccessibilityManager;
+ private final String mPackageName;
private View mTutorialView;
private Point mDisplaySize = new Point();
private Handler mUpdateHandler;
private ContentResolver mContentResolver;
private boolean mCanShowTutorial;
+ private String mStartOneHandedDescription;
+ private String mStopOneHandedDescription;
/**
* Container of the tutorial panel showing at outside region when one handed starting
@@ -72,9 +78,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
public OneHandedTutorialHandler(Context context) {
context.getDisplay().getRealSize(mDisplaySize);
+ mPackageName = context.getPackageName();
mContentResolver = context.getContentResolver();
mUpdateHandler = new Handler();
mWindowManager = context.getSystemService(WindowManager.class);
+ mAccessibilityManager = (AccessibilityManager)
+ context.getSystemService(Context.ACCESSIBILITY_SERVICE);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setClipChildren(false);
mTutorialAreaHeight = Math.round(mDisplaySize.y
@@ -84,6 +93,10 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
? false : true;
+ mStartOneHandedDescription = context.getResources().getString(
+ R.string.accessibility_action_start_one_handed);
+ mStopOneHandedDescription = context.getResources().getString(
+ R.string.accessibility_action_stop_one_handed);
if (mCanShowTutorial) {
createOrUpdateTutorialTarget();
}
@@ -94,13 +107,16 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
mUpdateHandler.post(() -> {
updateFinished(View.VISIBLE, 0f);
updateTutorialCount();
+ announcementForScreenReader(true);
});
}
@Override
public void onStopFinished(Rect bounds) {
- mUpdateHandler.post(() -> updateFinished(
- View.INVISIBLE, -mTargetViewContainer.getHeight()));
+ mUpdateHandler.post(() -> {
+ updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight());
+ announcementForScreenReader(false);
+ });
}
private void updateFinished(int visible, float finalPosition) {
@@ -121,6 +137,17 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback {
Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
}
+ private void announcementForScreenReader(boolean isStartOneHanded) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ final AccessibilityEvent event = AccessibilityEvent.obtain();
+ event.setPackageName(mPackageName);
+ event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ event.getText().add(isStartOneHanded
+ ? mStartOneHandedDescription : mStopOneHandedDescription);
+ mAccessibilityManager.sendAccessibilityEvent(event);
+ }
+ }
+
/**
* Adds the tutorial target view to the WindowManager and update its layout, so it's ready
* to be animated in.
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index cfba5d4f6aa2..a690840e91a9 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -735,8 +735,7 @@ void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
// ----------------------------------------------------------------------------
void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight,
- float boundsBottom, float totalAdvance) {
+ float y, float totalAdvance) {
if (count <= 0 || paint.nothingToDraw()) return;
Paint paintCopy(paint);
if (mPaintFilter) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 1df2b2671659..2cb850c83934 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -161,8 +161,7 @@ protected:
void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight,
- float boundsBottom, float totalAdvance) override;
+ float y, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
const Paint& paint, const SkPath& path, size_t start,
size_t end) override;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 2a377bbb83f2..2001b5620f84 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -84,13 +84,12 @@ static void simplifyPaint(int color, Paint* paint) {
class DrawTextFunctor {
public:
DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, const Paint& paint, float x,
- float y, minikin::MinikinRect& bounds, float totalAdvance)
+ float y, float totalAdvance)
: layout(layout)
, canvas(canvas)
, paint(paint)
, x(x)
, y(y)
- , bounds(bounds)
, totalAdvance(totalAdvance) {}
void operator()(size_t start, size_t end) {
@@ -114,19 +113,16 @@ public:
Paint outlinePaint(paint);
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
- canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, totalAdvance);
// inner
Paint innerPaint(paint);
simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
innerPaint.setStyle(SkPaint::kFill_Style);
- canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, totalAdvance);
} else {
// standard draw path
- canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, totalAdvance);
}
}
@@ -136,7 +132,6 @@ private:
const Paint& paint;
float x;
float y;
- minikin::MinikinRect& bounds;
float totalAdvance;
};
@@ -156,15 +151,12 @@ void Canvas::drawText(const uint16_t* text, int textSize, int start, int count,
x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
- minikin::MinikinRect bounds;
- layout.getBounds(&bounds);
-
// Set align to left for drawing, as we don't want individual
// glyphs centered or right-aligned; the offset above takes
// care of all alignment.
paint.setTextAlign(Paint::kLeft_Align);
- DrawTextFunctor f(layout, this, paint, x, y, bounds, layout.getAdvance());
+ DrawTextFunctor f(layout, this, paint, x, y, layout.getAdvance());
MinikinUtils::forFontRun(layout, &paint, f);
}
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 333567b0cf91..817c7ee9077f 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -288,8 +288,7 @@ protected:
* totalAdvance: used to define width of text decorations (underlines, strikethroughs).
*/
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const Paint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight,
- float boundsBottom, float totalAdvance) = 0;
+ float y,float totalAdvance) = 0;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
const Paint& paint, const SkPath& path, size_t start,
size_t end) = 0;
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 7cb77233846f..0a194f9dd666 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -224,7 +224,7 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat sigmaX,
- jfloat sigmaY, jlong shaderHandle) {
+ jfloat sigmaY, jlong shaderHandle, jint edgeTreatment) {
auto* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
auto* inputShader = reinterpret_cast<Shader*>(shaderHandle);
@@ -232,6 +232,7 @@ static jlong BlurShader_create(JNIEnv* env , jobject o, jlong matrixPtr, jfloat
sigmaX,
sigmaY,
inputShader,
+ static_cast<SkTileMode>(edgeTreatment),
matrix
);
return reinterpret_cast<jlong>(blurShader);
@@ -291,7 +292,7 @@ static const JNINativeMethod gBitmapShaderMethods[] = {
};
static const JNINativeMethod gBlurShaderMethods[] = {
- { "nativeCreate", "(JFFJ)J", (void*)BlurShader_create }
+ { "nativeCreate", "(JFFJI)J", (void*)BlurShader_create }
};
static const JNINativeMethod gLinearGradientMethods[] = {
diff --git a/libs/hwui/shader/BlurShader.cpp b/libs/hwui/shader/BlurShader.cpp
index fa10be100bca..2abd8714204b 100644
--- a/libs/hwui/shader/BlurShader.cpp
+++ b/libs/hwui/shader/BlurShader.cpp
@@ -20,13 +20,14 @@
#include "utils/Blur.h"
namespace android::uirenderer {
-BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix)
+BlurShader::BlurShader(float radiusX, float radiusY, Shader* inputShader, SkTileMode edgeTreatment,
+ const SkMatrix* matrix)
: Shader(matrix)
, skImageFilter(
SkImageFilters::Blur(
Blur::convertRadiusToSigma(radiusX),
Blur::convertRadiusToSigma(radiusY),
- SkTileMode::kClamp,
+ edgeTreatment,
inputShader ? inputShader->asSkImageFilter() : nullptr,
nullptr)
) { }
diff --git a/libs/hwui/shader/BlurShader.h b/libs/hwui/shader/BlurShader.h
index 9eb22bd11f4a..60a15898893e 100644
--- a/libs/hwui/shader/BlurShader.h
+++ b/libs/hwui/shader/BlurShader.h
@@ -30,8 +30,12 @@ public:
*
* This will blur the contents of the provided input shader if it is non-null, otherwise
* the source bitmap will be blurred instead.
+ *
+ * The edge treatment parameter determines how content near the edges of the source is to
+ * participate in the blur
*/
- BlurShader(float radiusX, float radiusY, Shader* inputShader, const SkMatrix* matrix);
+ BlurShader(float radiusX, float radiusY, Shader* inputShader, SkTileMode edgeTreatment,
+ const SkMatrix* matrix);
~BlurShader() override;
protected:
sk_sp<SkImageFilter> makeSkImageFilter() override;
diff --git a/media/Android.bp b/media/Android.bp
index 8895b3a9a2ba..828707b70e7b 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -1,85 +1,52 @@
aidl_interface {
name: "audio_common-aidl",
unstable: true,
- local_include_dir: "java",
+ local_include_dir: "aidl",
srcs: [
- "java/android/media/audio/common/AudioChannelMask.aidl",
- "java/android/media/audio/common/AudioConfig.aidl",
- "java/android/media/audio/common/AudioFormat.aidl",
- "java/android/media/audio/common/AudioOffloadInfo.aidl",
- "java/android/media/audio/common/AudioStreamType.aidl",
- "java/android/media/audio/common/AudioUsage.aidl",
+ "aidl/android/media/audio/common/AudioChannelMask.aidl",
+ "aidl/android/media/audio/common/AudioConfig.aidl",
+ "aidl/android/media/audio/common/AudioFormat.aidl",
+ "aidl/android/media/audio/common/AudioOffloadInfo.aidl",
+ "aidl/android/media/audio/common/AudioStreamType.aidl",
+ "aidl/android/media/audio/common/AudioUsage.aidl",
],
- backend:
- {
- cpp: {
- enabled: true,
- },
- java: {
- // Already generated as part of the entire media java library.
- enabled: false,
- },
- },
}
aidl_interface {
name: "media_permission-aidl",
unstable: true,
- local_include_dir: "java",
+ local_include_dir: "aidl",
srcs: [
- "java/android/media/permission/Identity.aidl",
+ "aidl/android/media/permission/Identity.aidl",
],
- backend:
- {
- cpp: {
- enabled: true,
- },
- java: {
- // Already generated as part of the entire media java library.
- enabled: false,
- },
- },
}
aidl_interface {
name: "soundtrigger_middleware-aidl",
unstable: true,
- local_include_dir: "java",
+ local_include_dir: "aidl",
srcs: [
- "java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl",
- "java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
- "java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
- "java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
- "java/android/media/soundtrigger_middleware/ModelParameter.aidl",
- "java/android/media/soundtrigger_middleware/ModelParameterRange.aidl",
- "java/android/media/soundtrigger_middleware/Phrase.aidl",
- "java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl",
- "java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl",
- "java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl",
- "java/android/media/soundtrigger_middleware/RecognitionConfig.aidl",
- "java/android/media/soundtrigger_middleware/RecognitionEvent.aidl",
- "java/android/media/soundtrigger_middleware/RecognitionMode.aidl",
- "java/android/media/soundtrigger_middleware/RecognitionStatus.aidl",
- "java/android/media/soundtrigger_middleware/SoundModel.aidl",
- "java/android/media/soundtrigger_middleware/SoundModelType.aidl",
- "java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
- "java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl",
- "java/android/media/soundtrigger_middleware/Status.aidl",
+ "aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl",
+ "aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl",
+ "aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl",
+ "aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl",
+ "aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl",
+ "aidl/android/media/soundtrigger_middleware/ModelParameter.aidl",
+ "aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl",
+ "aidl/android/media/soundtrigger_middleware/Phrase.aidl",
+ "aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl",
+ "aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl",
+ "aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl",
+ "aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl",
+ "aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl",
+ "aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl",
+ "aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl",
+ "aidl/android/media/soundtrigger_middleware/SoundModel.aidl",
+ "aidl/android/media/soundtrigger_middleware/SoundModelType.aidl",
+ "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
+ "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl",
+ "aidl/android/media/soundtrigger_middleware/Status.aidl",
],
- backend:
- {
- cpp: {
- enabled: true,
- },
- java: {
- // Already generated as part of the entire media java library.
- enabled: false,
- },
- ndk: {
- // Not currently needed, and disabled because of b/146172425
- enabled: false,
- },
- },
imports: [
"audio_common-aidl",
"media_permission-aidl",
diff --git a/media/OWNERS b/media/OWNERS
index c95ac6c210c0..36df3a05e0ee 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -9,6 +9,7 @@ hkuang@google.com
hunga@google.com
insun@google.com
jaewan@google.com
+jinpark@google.com
jmtrivi@google.com
jsharkey@android.com
klhyun@google.com
@@ -17,6 +18,3 @@ marcone@google.com
philburk@google.com
sungsoo@google.com
wonsik@google.com
-
-# For maintaining sync with AndroidX code
-per-file ExifInterface.java = jinpark@google.com, sungsoo@google.com
diff --git a/media/java/android/media/audio/common/AudioChannelMask.aidl b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
index b9b08e6921bc..b9b08e6921bc 100644
--- a/media/java/android/media/audio/common/AudioChannelMask.aidl
+++ b/media/aidl/android/media/audio/common/AudioChannelMask.aidl
diff --git a/media/java/android/media/audio/common/AudioConfig.aidl b/media/aidl/android/media/audio/common/AudioConfig.aidl
index 50dd796e1fa0..50dd796e1fa0 100644
--- a/media/java/android/media/audio/common/AudioConfig.aidl
+++ b/media/aidl/android/media/audio/common/AudioConfig.aidl
diff --git a/media/java/android/media/audio/common/AudioFormat.aidl b/media/aidl/android/media/audio/common/AudioFormat.aidl
index aadc8e26cce3..aadc8e26cce3 100644
--- a/media/java/android/media/audio/common/AudioFormat.aidl
+++ b/media/aidl/android/media/audio/common/AudioFormat.aidl
diff --git a/media/java/android/media/audio/common/AudioOffloadInfo.aidl b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
index ec10d71135ae..ec10d71135ae 100644
--- a/media/java/android/media/audio/common/AudioOffloadInfo.aidl
+++ b/media/aidl/android/media/audio/common/AudioOffloadInfo.aidl
diff --git a/media/java/android/media/audio/common/AudioStreamType.aidl b/media/aidl/android/media/audio/common/AudioStreamType.aidl
index c54566726350..c54566726350 100644
--- a/media/java/android/media/audio/common/AudioStreamType.aidl
+++ b/media/aidl/android/media/audio/common/AudioStreamType.aidl
diff --git a/media/java/android/media/audio/common/AudioUsage.aidl b/media/aidl/android/media/audio/common/AudioUsage.aidl
index ef348165b22c..ef348165b22c 100644
--- a/media/java/android/media/audio/common/AudioUsage.aidl
+++ b/media/aidl/android/media/audio/common/AudioUsage.aidl
diff --git a/media/java/android/media/permission/Identity.aidl b/media/aidl/android/media/permission/Identity.aidl
index 361497d59ea9..361497d59ea9 100644
--- a/media/java/android/media/permission/Identity.aidl
+++ b/media/aidl/android/media/permission/Identity.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/AudioCapabilities.aidl b/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
index 97a8849c7b07..97a8849c7b07 100644
--- a/media/java/android/media/soundtrigger_middleware/AudioCapabilities.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/AudioCapabilities.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl b/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
index 3dbc70556bd3..3dbc70556bd3 100644
--- a/media/java/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ConfidenceLevel.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
index 726af7681979..726af7681979 100644
--- a/media/java/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerCallback.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
index d1126b9006e0..d1126b9006e0 100644
--- a/media/java/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerMiddlewareService.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
index c4a57857dd3d..c4a57857dd3d 100644
--- a/media/java/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ISoundTriggerModule.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ModelParameter.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
index 09936278e93a..09936278e93a 100644
--- a/media/java/android/media/soundtrigger_middleware/ModelParameter.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ModelParameter.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/ModelParameterRange.aidl b/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
index d6948a87dc6d..d6948a87dc6d 100644
--- a/media/java/android/media/soundtrigger_middleware/ModelParameterRange.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/ModelParameterRange.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/OWNERS b/media/aidl/android/media/soundtrigger_middleware/OWNERS
index e5d037003ac4..e5d037003ac4 100644
--- a/media/java/android/media/soundtrigger_middleware/OWNERS
+++ b/media/aidl/android/media/soundtrigger_middleware/OWNERS
diff --git a/media/java/android/media/soundtrigger_middleware/Phrase.aidl b/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
index 98a489f8a6a9..98a489f8a6a9 100644
--- a/media/java/android/media/soundtrigger_middleware/Phrase.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/Phrase.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
index 6a3ec61d1ebf..6a3ec61d1ebf 100644
--- a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionEvent.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
index cb96bf37a95d..cb96bf37a95d 100644
--- a/media/java/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseRecognitionExtra.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
index 81028c1608ea..81028c1608ea 100644
--- a/media/java/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/PhraseSoundModel.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionConfig.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
index 5c0eeb1e32b1..5c0eeb1e32b1 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionConfig.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionConfig.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
index a237ec1aa3b3..a237ec1aa3b3 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionEvent.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionEvent.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionMode.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
index d8bfff4bec6f..d8bfff4bec6f 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionMode.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionMode.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/RecognitionStatus.aidl b/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
index d563edca547d..d563edca547d 100644
--- a/media/java/android/media/soundtrigger_middleware/RecognitionStatus.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/RecognitionStatus.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
index 81d8291e85aa..cee3635a1e3b 100644
--- a/media/java/android/media/soundtrigger_middleware/SoundModel.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundModel.aidl
@@ -16,6 +16,7 @@
package android.media.soundtrigger_middleware;
import android.media.soundtrigger_middleware.SoundModelType;
+import android.os.ParcelFileDescriptor;
/**
* Base sound model descriptor. This struct can be extended for various specific types by way of
@@ -32,7 +33,7 @@ parcelable SoundModel {
* was build for */
String vendorUuid;
/** Opaque data transparent to Android framework */
- FileDescriptor data;
+ ParcelFileDescriptor data;
/** Size of the above data, in bytes. */
int dataSize;
}
diff --git a/media/java/android/media/soundtrigger_middleware/SoundModelType.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
index f2abc9af7780..f2abc9af7780 100644
--- a/media/java/android/media/soundtrigger_middleware/SoundModelType.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundModelType.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
index 667135ff61b9..667135ff61b9 100644
--- a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
index 9c56e7b98b3f..9c56e7b98b3f 100644
--- a/media/java/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/SoundTriggerModuleProperties.aidl
diff --git a/media/java/android/media/soundtrigger_middleware/Status.aidl b/media/aidl/android/media/soundtrigger_middleware/Status.aidl
index c7623f5bf491..c7623f5bf491 100644
--- a/media/java/android/media/soundtrigger_middleware/Status.aidl
+++ b/media/aidl/android/media/soundtrigger_middleware/Status.aidl
diff --git a/media/java/android/media/AudioAttributes.aidl b/media/java/android/media/AudioAttributes.aidl
index 04587f9d48d4..88a6f50d2d3c 100644
--- a/media/java/android/media/AudioAttributes.aidl
+++ b/media/java/android/media/AudioAttributes.aidl
@@ -15,4 +15,4 @@
package android.media;
-parcelable AudioAttributes;
+@JavaOnlyStableParcelable parcelable AudioAttributes;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index e1e55c25b3fa..22b5ca53e7e9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -96,8 +96,8 @@ public class AudioManager {
private Context mOriginalContext;
private Context mApplicationContext;
private long mVolumeKeyUpTime;
- private final boolean mUseVolumeKeySounds;
- private final boolean mUseFixedVolume;
+ private boolean mUseFixedVolumeInitialized;
+ private boolean mUseFixedVolume;
private static final String TAG = "AudioManager";
private static final boolean DEBUG = false;
private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
@@ -711,8 +711,6 @@ public class AudioManager {
*/
@UnsupportedAppUsage
public AudioManager() {
- mUseVolumeKeySounds = true;
- mUseFixedVolume = false;
}
/**
@@ -721,10 +719,6 @@ public class AudioManager {
@UnsupportedAppUsage
public AudioManager(Context context) {
setContext(context);
- mUseVolumeKeySounds = getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_useVolumeKeySounds);
- mUseFixedVolume = getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_useFixedVolume);
}
private Context getContext() {
@@ -823,6 +817,18 @@ public class AudioManager {
* </ul>
*/
public boolean isVolumeFixed() {
+ synchronized (this) {
+ try {
+ if (!mUseFixedVolumeInitialized) {
+ mUseFixedVolume = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_useFixedVolume);
+ }
+ } catch (Exception e) {
+ } finally {
+ // only ever try once, so always consider initialized even if query failed
+ mUseFixedVolumeInitialized = true;
+ }
+ }
return mUseFixedVolume;
}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ddc7db771550..8845d6954db2 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -31,7 +31,6 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -599,7 +598,6 @@ public class ExifInterface {
private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@GuardedBy("sFormatter")
private static SimpleDateFormat sFormatter;
@GuardedBy("sFormatterTz")
@@ -1446,18 +1444,17 @@ public class ExifInterface {
sExifPointerTagMap.put(EXIF_POINTER_TAGS[5].number, IFD_TYPE_ORF_IMAGE_PROCESSING); // 8256
}
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private String mFilename;
private FileDescriptor mSeekableFileDescriptor;
private AssetManager.AssetInputStream mAssetInputStream;
private boolean mIsInputStream;
private int mMimeType;
private boolean mIsExifDataOnly;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(publicAlternatives = "Use {@link #getAttribute(java.lang.String)} "
+ + "instead.")
private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
private Set<Integer> mHandledIfdOffsets = new HashSet<>(EXIF_TAGS.length);
private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mHasThumbnail;
private boolean mHasThumbnailStrips;
private boolean mAreThumbnailStripsConsecutive;
@@ -2409,11 +2406,8 @@ public class ExifInterface {
}
/**
- * Returns parsed {@code DateTime} value, or -1 if unavailable or invalid.
- *
- * @hide
+ * Returns parsed {@link #TAG_DATETIME} value, or -1 if unavailable or invalid.
*/
- @UnsupportedAppUsage
public @CurrentTimeMillisLong long getDateTime() {
return parseDateTime(getAttribute(TAG_DATETIME),
getAttribute(TAG_SUBSEC_TIME),
@@ -2421,10 +2415,7 @@ public class ExifInterface {
}
/**
- * Returns parsed {@code DateTimeDigitized} value, or -1 if unavailable or
- * invalid.
- *
- * @hide
+ * Returns parsed {@link #TAG_DATETIME_DIGITIZED} value, or -1 if unavailable or invalid.
*/
public @CurrentTimeMillisLong long getDateTimeDigitized() {
return parseDateTime(getAttribute(TAG_DATETIME_DIGITIZED),
@@ -2433,12 +2424,8 @@ public class ExifInterface {
}
/**
- * Returns parsed {@code DateTimeOriginal} value, or -1 if unavailable or
- * invalid.
- *
- * @hide
+ * Returns parsed {@link #TAG_DATETIME_ORIGINAL} value, or -1 if unavailable or invalid.
*/
- @UnsupportedAppUsage
public @CurrentTimeMillisLong long getDateTimeOriginal() {
return parseDateTime(getAttribute(TAG_DATETIME_ORIGINAL),
getAttribute(TAG_SUBSEC_TIME_ORIGINAL),
@@ -2490,9 +2477,7 @@ public class ExifInterface {
/**
* Returns number of milliseconds since Jan. 1, 1970, midnight UTC.
* Returns -1 if the date time information if not available.
- * @hide
*/
- @UnsupportedAppUsage
public long getGpsDateTime() {
String date = getAttribute(TAG_GPS_DATESTAMP);
String time = getAttribute(TAG_GPS_TIMESTAMP);
@@ -2518,7 +2503,6 @@ public class ExifInterface {
}
/** {@hide} */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public static float convertRationalLatLonToFloat(String rationalString, String ref) {
try {
String [] parts = rationalString.split(",");
diff --git a/media/java/android/media/MediaMetadata.aidl b/media/java/android/media/MediaMetadata.aidl
index 66ee48304168..1d78da2a1b8e 100644
--- a/media/java/android/media/MediaMetadata.aidl
+++ b/media/java/android/media/MediaMetadata.aidl
@@ -15,4 +15,4 @@
package android.media;
-parcelable MediaMetadata;
+@JavaOnlyStableParcelable parcelable MediaMetadata;
diff --git a/media/java/android/media/MediaTranscodeManager.java b/media/java/android/media/MediaTranscodeManager.java
index e09241137541..21376bb0fecb 100644
--- a/media/java/android/media/MediaTranscodeManager.java
+++ b/media/java/android/media/MediaTranscodeManager.java
@@ -83,13 +83,13 @@ import java.util.concurrent.Executors;
<pre class=prettyprint>
TranscodingRequest request =
- new TranscodingRequest.Builder()
- .setSourceUri(srcUri)
- .setDestinationUri(dstUri)
- .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
- .setPriority(REALTIME)
- .setVideoTrackFormat(videoFormat)
- .build();
+ new TranscodingRequest.Builder()
+ .setSourceUri(srcUri)
+ .setDestinationUri(dstUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(REALTIME)
+ .setVideoTrackFormat(videoFormat)
+ .build();
}</pre>
TODO(hkuang): Add architecture diagram showing the transcoding service and api.
@@ -498,6 +498,20 @@ public final class MediaTranscodeManager {
/** Uri of the destination media file. */
private @NonNull Uri mDestinationUri;
+ /**
+ * The UID of the client that the TranscodingRequest is for. Only privileged caller could
+ * set this Uid as only they could do the transcoding on behalf of the client.
+ * -1 means not available.
+ */
+ private int mClientUid = -1;
+
+ /**
+ * The Pid of the client that the TranscodingRequest is for. Only privileged caller could
+ * set this Uid as only they could do the transcoding on behalf of the client.
+ * -1 means not available.
+ */
+ private int mClientPid = -1;
+
/** Type of the transcoding. */
private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
@@ -534,6 +548,8 @@ public final class MediaTranscodeManager {
private TranscodingRequest(Builder b) {
mSourceUri = b.mSourceUri;
mDestinationUri = b.mDestinationUri;
+ mClientUid = b.mClientUid;
+ mClientPid = b.mClientPid;
mPriority = b.mPriority;
mType = b.mType;
mVideoTrackFormat = b.mVideoTrackFormat;
@@ -554,6 +570,16 @@ public final class MediaTranscodeManager {
return mSourceUri;
}
+ /** Return the UID of the client that this request is for. -1 means not available. */
+ public int getClientUid() {
+ return mClientUid;
+ }
+
+ /** Return the PID of the client that this request is for. -1 means not available. */
+ public int getClientPid() {
+ return mClientPid;
+ }
+
/** Return destination uri of the transcoding. */
@NonNull
public Uri getDestinationUri() {
@@ -592,6 +618,8 @@ public final class MediaTranscodeManager {
parcel.transcodingType = mType;
parcel.sourceFilePath = mSourceUri.toString();
parcel.destinationFilePath = mDestinationUri.toString();
+ parcel.clientUid = mClientUid;
+ parcel.clientPid = mClientPid;
parcel.requestedVideoTrackFormat = convertToVideoTrackFormat(mVideoTrackFormat);
if (mTestConfig != null) {
parcel.isForTesting = true;
@@ -667,6 +695,8 @@ public final class MediaTranscodeManager {
public static final class Builder {
private @NonNull Uri mSourceUri;
private @NonNull Uri mDestinationUri;
+ private int mClientUid = -1;
+ private int mClientPid = -1;
private @TranscodingType int mType = TRANSCODING_TYPE_UNKNOWN;
private @TranscodingPriority int mPriority = PRIORITY_UNKNOWN;
private @Nullable MediaFormat mVideoTrackFormat;
@@ -710,6 +740,38 @@ public final class MediaTranscodeManager {
}
/**
+ * Specify the UID of the client that this request is for.
+ * @param uid client Uid.
+ * @return The same builder instance.
+ * @throws IllegalArgumentException if uid is invalid.
+ * TODO(hkuang): Check the permission if it is allowed.
+ */
+ @NonNull
+ public Builder setClientUid(int uid) {
+ if (uid <= 0) {
+ throw new IllegalArgumentException("Invalid Uid");
+ }
+ mClientUid = uid;
+ return this;
+ }
+
+ /**
+ * Specify the PID of the client that this request is for.
+ * @param pid client Pid.
+ * @return The same builder instance.
+ * @throws IllegalArgumentException if pid is invalid.
+ * TODO(hkuang): Check the permission if it is allowed.
+ */
+ @NonNull
+ public Builder setClientPid(int pid) {
+ if (pid <= 0) {
+ throw new IllegalArgumentException("Invalid pid");
+ }
+ mClientPid = pid;
+ return this;
+ }
+
+ /**
* Specifies the priority of the transcoding.
*
* @param priority Must be one of the {@code PRIORITY_*}
@@ -1225,6 +1287,50 @@ public final class MediaTranscodeManager {
}
}
+ @Override
+ public String toString() {
+ String result;
+ String status;
+
+ switch (mResult) {
+ case RESULT_NONE:
+ result = "RESULT_NONE";
+ break;
+ case RESULT_SUCCESS:
+ result = "RESULT_SUCCESS";
+ break;
+ case RESULT_ERROR:
+ result = "RESULT_ERROR";
+ break;
+ case RESULT_CANCELED:
+ result = "RESULT_CANCELED";
+ break;
+ default:
+ result = String.valueOf(mResult);
+ break;
+ }
+
+ switch (mStatus) {
+ case STATUS_PENDING:
+ status = "STATUS_PENDING";
+ break;
+ case STATUS_PAUSED:
+ status = "STATUS_PAUSED";
+ break;
+ case STATUS_RUNNING:
+ status = "STATUS_RUNNING";
+ break;
+ case STATUS_FINISHED:
+ status = "STATUS_FINISHED";
+ break;
+ default:
+ status = String.valueOf(mStatus);
+ break;
+ }
+ return String.format(" Job: {id: %d, status: %s, result: %s, progress: %d}",
+ mJobId, status, result, mProgress);
+ }
+
private void updateProgress(int newProgress) {
synchronized (mLock) {
mProgress = newProgress;
@@ -1275,6 +1381,8 @@ public final class MediaTranscodeManager {
// Converts the request to TranscodingRequestParcel.
TranscodingRequestParcel requestParcel = transcodingRequest.writeToParcel();
+ Log.i(TAG, "Getting transcoding request " + transcodingRequest.getSourceUri());
+
// Submits the request to MediaTranscoding service.
try {
TranscodingJobParcel jobParcel = new TranscodingJobParcel();
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index 9e48f1e05391..35cfaca8562a 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -538,7 +538,7 @@ import java.util.List;
handler = new Handler(Looper.getMainLooper());
}
mSessionManager.addOnActiveSessionsChangedListener(mSessionListener, listenerComponent,
- UserHandle.myUserId(), handler);
+ handler);
mSessionListener.onActiveSessionsChanged(mSessionManager
.getActiveSessions(listenerComponent));
if (DEBUG) {
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 9494295e4bd9..3acb9516054e 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
@@ -262,18 +263,14 @@ public final class MediaSessionManager {
}
/**
- * Add a listener to be notified when the list of active sessions
- * changes.This requires the
- * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app. You may also retrieve this list if your app is an
- * enabled notification listener using the
- * {@link NotificationListenerService} APIs, in which case you must pass the
- * {@link ComponentName} of your enabled listener. Updates will be posted to
- * the thread that registered the listener.
+ * Add a listener to be notified when the list of active sessions changes. This requires the
+ * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
+ * app. You may also retrieve this list if your app is an enabled notification listener using
+ * the {@link NotificationListenerService} APIs, in which case you must pass the
+ * {@link ComponentName} of your enabled listener.
*
* @param sessionListener The listener to add.
- * @param notificationListener The enabled notification listener component.
- * May be null.
+ * @param notificationListener The enabled notification listener component. May be null.
*/
public void addOnActiveSessionsChangedListener(
@NonNull OnActiveSessionsChangedListener sessionListener,
@@ -282,18 +279,15 @@ public final class MediaSessionManager {
}
/**
- * Add a listener to be notified when the list of active sessions
- * changes.This requires the
- * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app. You may also retrieve this list if your app is an
- * enabled notification listener using the
- * {@link NotificationListenerService} APIs, in which case you must pass the
- * {@link ComponentName} of your enabled listener. Updates will be posted to
- * the handler specified or to the caller's thread if the handler is null.
+ * Add a listener to be notified when the list of active sessions changes. This requires the
+ * {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be held by the calling
+ * app. You may also retrieve this list if your app is an enabled notification listener using
+ * the {@link NotificationListenerService} APIs, in which case you must pass the
+ * {@link ComponentName} of your enabled listener. Updates will be posted to the handler
+ * specified or to the caller's thread if the handler is null.
*
* @param sessionListener The listener to add.
- * @param notificationListener The enabled notification listener component.
- * May be null.
+ * @param notificationListener The enabled notification listener component. May be null.
* @param handler The handler to post events to.
*/
public void addOnActiveSessionsChangedListener(
@@ -304,21 +298,24 @@ public final class MediaSessionManager {
}
/**
- * Add a listener to be notified when the list of active sessions
- * changes.This requires the
- * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
- * the calling app. You may also retrieve this list if your app is an
- * enabled notification listener using the
- * {@link NotificationListenerService} APIs, in which case you must pass the
- * {@link ComponentName} of your enabled listener.
+ * Add a listener to be notified when the list of active sessions changes for the given user.
+ * The calling app must have the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
+ * permission if it wants to call this method for a user that is not running the app.
+ * <p>
+ * This requires the {@link android.Manifest.permission#MEDIA_CONTENT_CONTROL} permission be
+ * held by the calling app. You may also retrieve this list if your app is an enabled
+ * notification listener using the {@link NotificationListenerService} APIs, in which case you
+ * must pass the {@link ComponentName} of your enabled listener. Updates will be posted to the
+ * handler specified or to the caller's thread if the handler is null.
*
* @param sessionListener The listener to add.
- * @param notificationListener The enabled notification listener component.
- * May be null.
+ * @param notificationListener The enabled notification listener component. May be null.
* @param userId The userId to listen for changes on.
* @param handler The handler to post updates on.
* @hide
*/
+ @SuppressLint({"ExecutorRegistration", "SamShouldBeLast"})
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void addOnActiveSessionsChangedListener(
@NonNull OnActiveSessionsChangedListener sessionListener,
@Nullable ComponentName notificationListener, int userId, @Nullable Handler handler) {
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
index 33d6d64c7f37..21ed840c7313 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodeManagerTest.java
@@ -203,6 +203,42 @@ public class MediaTranscodeManagerTest
}
/**
+ * Verify that setting invalid pid will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingWithInvalidClientPid() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(mDestinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setClientPid(-1)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
+ * Verify that setting invalid uid will throw exception.
+ */
+ @Test
+ public void testCreateTranscodingWithInvalidClientUid() throws Exception {
+ assertThrows(IllegalArgumentException.class, () -> {
+ TranscodingRequest request =
+ new TranscodingRequest.Builder()
+ .setSourceUri(mSourceHEVCVideoUri)
+ .setDestinationUri(mDestinationUri)
+ .setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
+ .setClientUid(-1)
+ .setVideoTrackFormat(createMediaFormat())
+ .build();
+ });
+ }
+
+ /**
* Verify that setting null source uri will throw exception.
*/
@Test
@@ -425,16 +461,24 @@ public class MediaTranscodeManagerTest
MediaFormat videoTrackFormat = resolver.resolveVideoFormat();
assertNotNull(videoTrackFormat);
+ int pid = android.os.Process.myPid();
+ int uid = android.os.Process.myUid();
+
TranscodingRequest request =
new TranscodingRequest.Builder()
.setSourceUri(mSourceHEVCVideoUri)
.setDestinationUri(destinationUri)
.setType(MediaTranscodeManager.TRANSCODING_TYPE_VIDEO)
+ .setClientPid(pid)
+ .setClientUid(uid)
.setPriority(MediaTranscodeManager.PRIORITY_REALTIME)
.setVideoTrackFormat(videoTrackFormat)
.build();
Executor listenerExecutor = Executors.newSingleThreadExecutor();
+ assertEquals(pid, request.getClientPid());
+ assertEquals(uid, request.getClientUid());
+
Log.i(TAG, "transcoding to " + videoTrackFormat);
TranscodingJob job = mMediaTranscodeManager.enqueueRequest(request, listenerExecutor,
diff --git a/non-updatable-api/Android.bp b/non-updatable-api/Android.bp
new file mode 100644
index 000000000000..4037781c1844
--- /dev/null
+++ b/non-updatable-api/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_visibility: ["//visibility:private"],
+}
+
+filegroup {
+ name: "non-updatable-current.txt",
+ srcs: ["current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+ name: "non-updatable-system-current.txt",
+ srcs: ["system-current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
+
+filegroup {
+ name: "non-updatable-module-lib-current.txt",
+ srcs: ["module-lib-current.txt"],
+ visibility: ["//frameworks/base/api"],
+}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 80300611c7f2..2d5d48f3f09b 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -6138,6 +6138,7 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
+ field public static final int FLAG_MUTABLE = 33554432; // 0x2000000
field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -14292,6 +14293,7 @@ package android.graphics {
public final class BlurShader extends android.graphics.Shader {
ctor public BlurShader(float, float, @Nullable android.graphics.Shader);
+ ctor public BlurShader(float, float, @Nullable android.graphics.Shader, @NonNull android.graphics.Shader.TileMode);
}
public class Camera {
@@ -15177,6 +15179,20 @@ package android.graphics {
ctor public PaintFlagsDrawFilter(int, int);
}
+ public final class ParcelableColorSpace extends android.graphics.ColorSpace implements android.os.Parcelable {
+ ctor public ParcelableColorSpace(@NonNull android.graphics.ColorSpace);
+ method public int describeContents();
+ method @NonNull public float[] fromXyz(@NonNull float[]);
+ method @NonNull public android.graphics.ColorSpace getColorSpace();
+ method public float getMaxValue(int);
+ method public float getMinValue(int);
+ method public static boolean isParcelable(@NonNull android.graphics.ColorSpace);
+ method public boolean isWideGamut();
+ method @NonNull public float[] toXyz(@NonNull float[]);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.graphics.ParcelableColorSpace> CREATOR;
+ }
+
public class Path {
ctor public Path();
ctor public Path(@Nullable android.graphics.Path);
@@ -15612,6 +15628,7 @@ package android.graphics {
public enum Shader.TileMode {
enum_constant public static final android.graphics.Shader.TileMode CLAMP;
+ enum_constant public static final android.graphics.Shader.TileMode DECAL;
enum_constant public static final android.graphics.Shader.TileMode MIRROR;
enum_constant public static final android.graphics.Shader.TileMode REPEAT;
}
@@ -24895,6 +24912,10 @@ package android.media {
method public double getAttributeDouble(@NonNull String, double);
method public int getAttributeInt(@NonNull String, int);
method @Nullable public long[] getAttributeRange(@NonNull String);
+ method public long getDateTime();
+ method public long getDateTimeDigitized();
+ method public long getDateTimeOriginal();
+ method public long getGpsDateTime();
method public boolean getLatLong(float[]);
method public byte[] getThumbnail();
method public android.graphics.Bitmap getThumbnailBitmap();
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 3810325c982f..85136df0d1ad 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -66,6 +66,7 @@ package android.media.session {
}
public final class MediaSessionManager {
+ method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 10fe058bb76f..e27ca09f8e86 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4339,6 +4339,8 @@ package android.media {
}
public static final class MediaTranscodeManager.TranscodingRequest {
+ method public int getClientPid();
+ method public int getClientUid();
method @NonNull public android.net.Uri getDestinationUri();
method public int getPriority();
method @NonNull public android.net.Uri getSourceUri();
@@ -4349,6 +4351,8 @@ package android.media {
public static final class MediaTranscodeManager.TranscodingRequest.Builder {
ctor public MediaTranscodeManager.TranscodingRequest.Builder();
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest build();
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientPid(int);
+ method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setClientUid(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setDestinationUri(@NonNull android.net.Uri);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setPriority(int);
method @NonNull public android.media.MediaTranscodeManager.TranscodingRequest.Builder setSourceUri(@NonNull android.net.Uri);
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index 2c9788955bfa..e7295aa6383d 100644
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
@@ -25,7 +25,8 @@
<ViewStub android:id="@+id/notification_panel_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout="@layout/notification_panel_container"/>
+ android:layout="@layout/notification_panel_container"
+ android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/>
<ViewStub android:id="@+id/keyguard_stub"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml
index 28b8eadf9750..fe060ac8e707 100644
--- a/packages/CarSystemUI/res/values/dimens.xml
+++ b/packages/CarSystemUI/res/values/dimens.xml
@@ -207,6 +207,12 @@
<dimen name="car_navigation_bar_width">760dp</dimen>
<dimen name="car_left_navigation_bar_width">96dp</dimen>
<dimen name="car_right_navigation_bar_width">96dp</dimen>
+ <!-- In order to change the height of the bottom nav bar, overlay navigation_bar_height in
+ frameworks/base/core/res/res instead. -->
+ <dimen name="car_bottom_navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
+ <!-- In order to change the height of the top nav bar, overlay status_bar_height in
+ frameworks/base/core/res/res instead. -->
+ <dimen name="car_top_navigation_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="car_user_switcher_container_height">420dp</dimen>
<!-- This must be the negative of car_user_switcher_container_height for the animation. -->
diff --git a/packages/CarSystemUI/res/values/strings.xml b/packages/CarSystemUI/res/values/strings.xml
index fbdb5167fade..06ae7cfd6d1b 100644
--- a/packages/CarSystemUI/res/values/strings.xml
+++ b/packages/CarSystemUI/res/values/strings.xml
@@ -22,6 +22,8 @@
<string name="hvac_min_text">Min</string>
<!-- String to represent largest setting of an HVAC system [CHAR LIMIT=10]-->
<string name="hvac_max_text">Max</string>
+ <!-- String to display when no HVAC temperature is available -->
+ <string name="hvac_null_temp_text" translatable="false">--</string>
<!-- Text for voice recognition toast. [CHAR LIMIT=60] -->
<string name="voice_recognition_toast">Voice recognition now handled by connected Bluetooth device</string>
<!-- Name of Guest Profile. [CHAR LIMIT=35] -->
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
index 85d4ceb81eeb..af2a1d36bbd7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/hvac/AdjustableTemperatureView.java
@@ -40,6 +40,9 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu
private float mMinTempC;
private float mMaxTempC;
private String mTempFormat;
+ private String mNullTempText;
+ private String mMinTempText;
+ private String mMaxTempText;
private boolean mDisplayInFahrenheit = false;
private HvacController mHvacController;
@@ -59,6 +62,9 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu
mTempFormat = getResources().getString(R.string.hvac_temperature_format);
mMinTempC = getResources().getFloat(R.dimen.hvac_min_value_celsius);
mMaxTempC = getResources().getFloat(R.dimen.hvac_max_value_celsius);
+ mNullTempText = getResources().getString(R.string.hvac_null_temp_text);
+ mMinTempText = getResources().getString(R.string.hvac_min_text);
+ mMaxTempText = getResources().getString(R.string.hvac_max_text);
initializeButtons();
}
@@ -69,12 +75,23 @@ public class AdjustableTemperatureView extends LinearLayout implements Temperatu
@Override
public void setTemp(float tempC) {
- if (tempC > mMaxTempC || tempC < mMinTempC) {
- return;
- }
if (mTempTextView == null) {
mTempTextView = findViewById(R.id.hvac_temperature_text);
}
+ if (Float.isNaN(tempC)) {
+ mTempTextView.setText(mNullTempText);
+ return;
+ }
+ if (tempC <= mMinTempC) {
+ mTempTextView.setText(mMinTempText);
+ mCurrentTempC = mMinTempC;
+ return;
+ }
+ if (tempC >= mMaxTempC) {
+ mTempTextView.setText(mMaxTempText);
+ mCurrentTempC = mMaxTempC;
+ return;
+ }
mTempTextView.setText(String.format(mTempFormat,
mDisplayInFahrenheit ? convertToFahrenheit(tempC) : tempC));
mCurrentTempC = tempC;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
index 078196e18b88..dfda4e6b2635 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -216,7 +216,7 @@ public class SystemBarConfigs {
new SystemBarConfigBuilder()
.setSide(TOP)
.setGirth(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height))
+ R.dimen.car_top_navigation_bar_height))
.setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
.setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
.setHideForKeyboard(mResources.getBoolean(
@@ -230,7 +230,7 @@ public class SystemBarConfigs {
new SystemBarConfigBuilder()
.setSide(BOTTOM)
.setGirth(mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height))
+ R.dimen.car_bottom_navigation_bar_height))
.setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
.setZOrder(
mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index c7155f4b21d2..e8b332149864 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -16,8 +16,6 @@
package com.android.systemui.car.notification;
-import static android.view.WindowInsets.Type.navigationBars;
-
import android.app.ActivityManager;
import android.car.Car;
import android.car.drivingstate.CarUxRestrictionsManager;
@@ -25,6 +23,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.inputmethodservice.InputMethodService;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.GestureDetector;
@@ -82,6 +82,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
private final StatusBarStateController mStatusBarStateController;
private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
private final NotificationVisibilityLogger mNotificationVisibilityLogger;
+ private final int mNavBarHeight;
private float mInitialBackgroundAlpha;
private float mBackgroundAlphaDiff;
@@ -138,7 +139,10 @@ public class NotificationPanelViewController extends OverlayPanelViewController
mStatusBarStateController = statusBarStateController;
mNotificationVisibilityLogger = notificationVisibilityLogger;
+ mNavBarHeight = mResources.getDimensionPixelSize(R.dimen.car_bottom_navigation_bar_height);
+
mCommandQueue.addCallback(this);
+
// Notification background setup.
mInitialBackgroundAlpha = (float) mResources.getInteger(
R.integer.config_initialNotificationBackgroundAlpha) / 100;
@@ -179,6 +183,21 @@ public class NotificationPanelViewController extends OverlayPanelViewController
}
}
+ @Override
+ public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition,
+ boolean showImeSwitcher) {
+ if (mContext.getDisplayId() != displayId) {
+ return;
+ }
+ boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
+ int bottomMargin = isKeyboardVisible ? 0 : mNavBarHeight;
+ ViewGroup container = (ViewGroup) getLayout();
+ ViewGroup.MarginLayoutParams params =
+ (ViewGroup.MarginLayoutParams) container.getLayoutParams();
+ params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
+ container.setLayoutParams(params);
+ }
+
// OverlayViewController
@Override
@@ -204,7 +223,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
@Override
protected int getInsetTypesToFit() {
- return navigationBars();
+ return 0;
}
@Override
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
index a3a55aae5f18..fe071d54fb10 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/AdjustableTemperatureViewTest.java
@@ -98,6 +98,48 @@ public class AdjustableTemperatureViewTest extends SysuiTestCase {
}
@Test
+ public void setTemp_tempNaN_setsTextToNaNText() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ Float.NaN);
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(),
+ getContext().getResources().getString(R.string.hvac_null_temp_text));
+ }
+
+ @Test
+ public void setTemp_tempBelowMin_setsTextToMinTempText() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ getContext().getResources().getFloat(R.dimen.hvac_min_value_celsius));
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(),
+ getContext().getResources().getString(R.string.hvac_min_text));
+ }
+
+ @Test
+ public void setTemp_tempAboveMax_setsTextToMaxTempText() {
+ when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
+ anyInt())).thenReturn(true);
+ when(mCarPropertyManager.getFloatProperty(eq(HVAC_TEMPERATURE_SET), anyInt())).thenReturn(
+ getContext().getResources().getFloat(R.dimen.hvac_max_value_celsius));
+
+ mHvacController.addTemperatureViewToController(mAdjustableTemperatureView);
+
+ TextView tempText = mAdjustableTemperatureView.findViewById(R.id.hvac_temperature_text);
+ assertEquals(tempText.getText(),
+ getContext().getResources().getString(R.string.hvac_max_text));
+ }
+
+ @Test
public void setTemperatureToFahrenheit_callsViewSetDisplayInFahrenheit() {
when(mCarPropertyManager.isPropertyAvailable(eq(HVAC_TEMPERATURE_SET),
anyInt())).thenReturn(true);
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index 4bc7bf6e5d1f..462a6a9bb7ac 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Switserse Duits"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgies"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaars"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaars, foneties"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiaans"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Deens"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noors"</string>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 7a4ffeff433a..1559fa890bcd 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"የስዊዝ ጀርመን"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ቤልጂየም"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ቡልጋሪያ"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ቡልጋሪያኛ፣ ፎነቲክ"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ጣሊያንኛ"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ዴኒሽ"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ኖርዌጂያ"</string>
diff --git a/packages/InputDevices/res/values-as/strings.xml b/packages/InputDevices/res/values-as/strings.xml
index a63821e76633..49fbef92c114 100644
--- a/packages/InputDevices/res/values-as/strings.xml
+++ b/packages/InputDevices/res/values-as/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ছুইছ জাৰ্মান"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"বেলজিয়ান"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"বুলগেৰিয়ান"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"বুলগেৰিয়ান ফ’নেটিক"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ইটালিয়ান"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ডেনিশ্ব"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ন\'ৰৱেয়ান"</string>
diff --git a/packages/InputDevices/res/values-az/strings.xml b/packages/InputDevices/res/values-az/strings.xml
index 16badc456e73..c5a1e1ee2e2e 100644
--- a/packages/InputDevices/res/values-az/strings.xml
+++ b/packages/InputDevices/res/values-az/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"İsveçrə Almanı"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belçikalı"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bolqar"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bolqar dili, Fonetika"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"İtalyan"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danimarkalı"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norveçli"</string>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
index 95ef45916031..16f1cb2fc591 100644
--- a/packages/InputDevices/res/values-b+sr+Latn/strings.xml
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švajcarsko nemačka"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarska"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarska fonetska"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanska"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-be/strings.xml b/packages/InputDevices/res/values-be/strings.xml
index 63b899af1c98..6b0523f2bdf8 100644
--- a/packages/InputDevices/res/values-be/strings.xml
+++ b/packages/InputDevices/res/values-be/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Нямецкая (Швейцарыя)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Бельгійская"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Балгарская"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Балгарская фанетычная"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Італьянская"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Дацкая"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Нарвежская"</string>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index 90b7f6c5e9d3..a7088c930395 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"швейцарски немски"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"белгийски"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"български"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Българска фонетична клавиатура"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"италиански"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"датски"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвежки"</string>
diff --git a/packages/InputDevices/res/values-bs/strings.xml b/packages/InputDevices/res/values-bs/strings.xml
index f6a229c34eb4..b92ac8cad498 100644
--- a/packages/InputDevices/res/values-bs/strings.xml
+++ b/packages/InputDevices/res/values-bs/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarski njemački"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijski"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarski"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarski, fonetski"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanski"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"danski"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveški"</string>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index ec3b247ac6d3..a5b5e10129d4 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemany suís"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgar"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgar, fonètic"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italià"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danès"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruec"</string>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index dbe685cb2329..cf2aecf1783a 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Schweizertysk"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisk"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarsk"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarsk, fonetisk"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiensk"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dansk"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norsk"</string>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index fd7fca014548..1e786855ac25 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Schweizerdeutsch"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisch"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarisch"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarisch – phonetisch"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienisch"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dänisch"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norwegisch"</string>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 8bdd6f8bc967..eb2cc9b09a09 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Γερμανικά Ελβετίας"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Βελγικά"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Βουλγαρικά"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Βουλγαρικά (Φωνητικό)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Ιταλικά"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Δανικά"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Νορβηγικά"</string>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 5319f968afc3..e8d6597f0e57 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán de Suiza"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro fonético"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danés"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruego"</string>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 95b3b1c80cdf..9396e460eba1 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán suizo"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro (fonético)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danés"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruego"</string>
diff --git a/packages/InputDevices/res/values-et/strings.xml b/packages/InputDevices/res/values-et/strings.xml
index a5fb8ac08502..cf28e9f66dae 100644
--- a/packages/InputDevices/res/values-et/strings.xml
+++ b/packages/InputDevices/res/values-et/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Šveitsisaksa"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgia"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaaria"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaaria, foneetiline"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Itaalia"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Taani"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norra"</string>
diff --git a/packages/InputDevices/res/values-eu/strings.xml b/packages/InputDevices/res/values-eu/strings.xml
index 1c75a7c0f67f..1e080fc83141 100644
--- a/packages/InputDevices/res/values-eu/strings.xml
+++ b/packages/InputDevices/res/values-eu/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemana (Suitza)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgikarra"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgariarra"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariarra, fonetikoa"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiarra"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Daniarra"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegiarra"</string>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index ca7d43a1400f..5cb237e35053 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"آلمانی سوئیسی"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"بلژیکی"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"بلغاری"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"بلغاری، آوایی"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ایتالیایی"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"دانمارکی"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"نروژی"</string>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 2878c78318f7..da7210657381 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"sveitsinsaksa"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgialainen"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulgaria"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bulgaria, foneettinen"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"italia"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"tanska"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norja"</string>
diff --git a/packages/InputDevices/res/values-gl/strings.xml b/packages/InputDevices/res/values-gl/strings.xml
index e1ca7cfefa1c..40ede04c8e05 100644
--- a/packages/InputDevices/res/values-gl/strings.xml
+++ b/packages/InputDevices/res/values-gl/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemán suízo"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarqués"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noruegués"</string>
diff --git a/packages/InputDevices/res/values-gu/strings.xml b/packages/InputDevices/res/values-gu/strings.xml
index bc2ee8303290..631fc1497ce4 100644
--- a/packages/InputDevices/res/values-gu/strings.xml
+++ b/packages/InputDevices/res/values-gu/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"સ્વિસ જર્મન"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"બેલ્જિયન"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"બલ્ગેરિયન"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"બલ્ગેરિયન ફોનેટિક"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ઇટાલિયન"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ડેનિશ"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"નોર્વેજીયન"</string>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index 0430f8662014..aff2a37c2b7f 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarsko-njemačka"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarska"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bugarska (fonetska)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"talijanska"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 76d10f544280..50d667b40b62 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"svájci német"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bolgár"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bolgár fonetikus"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"olasz"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"dán"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norvég"</string>
diff --git a/packages/InputDevices/res/values-hy/strings.xml b/packages/InputDevices/res/values-hy/strings.xml
index fa4e24550639..4a6fe2b3be4f 100644
--- a/packages/InputDevices/res/values-hy/strings.xml
+++ b/packages/InputDevices/res/values-hy/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Շվեյցարական գերմաներեն"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Բելգիական"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Բուլղարերեն"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"բուլղարերեն (հնչյունային)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Իտալերեն"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Դանիերեն"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Նորվեգերեն"</string>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index f5d173a338a0..90ba97d16f6a 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Jerman Swiss"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgia"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaria"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaria, Fonetik"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italia"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Denmark"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norwegia"</string>
diff --git a/packages/InputDevices/res/values-is/strings.xml b/packages/InputDevices/res/values-is/strings.xml
index 09eedd300177..0889b21f3a64 100644
--- a/packages/InputDevices/res/values-is/strings.xml
+++ b/packages/InputDevices/res/values-is/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Svissneskt-þýskt"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgískt"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgarskt"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgarskt hljóðritunarlyklaborð"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Ítalskt"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norskt"</string>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index e15c01ff6a62..77f78c6f49d0 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tedesco svizzero"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgara, fonetica"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danese"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegese"</string>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 4abdf87ec4d4..52641b2ba1ff 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"גרמנית שוויצרית"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"בלגית"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"בולגרית"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"בולגרית פונטית"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"איטלקית"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"דנית"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"נורווגית"</string>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index 606ab3cd2239..2961548599a6 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ドイツ語(スイス)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ベルギー語"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ブルガリア語"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ブルガリア語(表音)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"イタリア語"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"デンマーク語"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ノルウェー語"</string>
diff --git a/packages/InputDevices/res/values-ka/strings.xml b/packages/InputDevices/res/values-ka/strings.xml
index b4b1a2df4d30..2ccfeb2f635f 100644
--- a/packages/InputDevices/res/values-ka/strings.xml
+++ b/packages/InputDevices/res/values-ka/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"შვეიცარიული გერმანული"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ბელგიური"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ბულგარული"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ბულგარული ფონეტიკური"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"იტალიური"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"დანიური"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ნორვეგიული"</string>
diff --git a/packages/InputDevices/res/values-kn/strings.xml b/packages/InputDevices/res/values-kn/strings.xml
index 8f62eb36a1f6..1e3c6932c3d4 100644
--- a/packages/InputDevices/res/values-kn/strings.xml
+++ b/packages/InputDevices/res/values-kn/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ಸ್ವಿಸ್ ಜರ್ಮನ್"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ಬೆಲ್ಜಿಯನ್"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ಬಲ್ಗೇರಿಯನ್‌"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ಬಲ್ಗೇರಿಯನ್ ಫೋನೆಟಿಕ್‌‌"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ಇಟಾಲಿಯನ್"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ಡ್ಯಾನಿಶ್"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ನಾರ್ವೇಜಿಯನ್"</string>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index b1f658202c46..147050462eab 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"독일어(스위스)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"벨기에어"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"불가리아어"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"불가리아어, 표음"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"이탈리아어"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"덴마크어"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"노르웨이어"</string>
diff --git a/packages/InputDevices/res/values-ky/strings.xml b/packages/InputDevices/res/values-ky/strings.xml
index bc521a2cd6cb..cb9dbb2f0abb 100644
--- a/packages/InputDevices/res/values-ky/strings.xml
+++ b/packages/InputDevices/res/values-ky/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Немис (Швейцария)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Белгия"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Болгар"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгарча, фонетикалык"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Италия"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Дания"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Норвег"</string>
diff --git a/packages/InputDevices/res/values-lo/strings.xml b/packages/InputDevices/res/values-lo/strings.xml
index edb59f3964ed..4ae4b7d9c58b 100644
--- a/packages/InputDevices/res/values-lo/strings.xml
+++ b/packages/InputDevices/res/values-lo/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ສະວິສ ເຢຍລະມັນ"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ເບວຢ້ຽນ"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ຮັງກາຣຽນ"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ບັງກາຣຽນ, ການອອກສຽງ"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ອິຕາລຽນ"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ເດັນນິຊ"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ນໍເວກຽນ"</string>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index f33eb42e6a4f..d2aef7f057db 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Šveicarijos vokiečių k."</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgų k."</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarų k."</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Fonetinė bulgarų"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italų k."</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danų k."</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegų k."</string>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 4f47a3ba65db..8f3ff0ab2264 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Vācu (Šveice)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Beļģu"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgāru"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgāru, fonētiskā"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Itāļu"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dāņu"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvēģu"</string>
diff --git a/packages/InputDevices/res/values-ml/strings.xml b/packages/InputDevices/res/values-ml/strings.xml
index 65fbf22d5fe7..9e5344367eae 100644
--- a/packages/InputDevices/res/values-ml/strings.xml
+++ b/packages/InputDevices/res/values-ml/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"സ്വിസ് ജര്‍മന്‍"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ബെൽജിയൻ"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ബൾഗേറിയൻ"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ബൾഗേറിയൻ, ഉച്ചാരണശബ്‌ദം"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ഇറ്റാലിയൻ"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ഡാനിഷ്"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"നോർവീജിയൻ"</string>
diff --git a/packages/InputDevices/res/values-mn/strings.xml b/packages/InputDevices/res/values-mn/strings.xml
index a8fc6615f4c1..18c2faf7e464 100644
--- a/packages/InputDevices/res/values-mn/strings.xml
+++ b/packages/InputDevices/res/values-mn/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Швейцарийн Герман"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Бельги"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Болгар"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгар хэл, Авиа зүй"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Итали"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Дани"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Норвеги"</string>
diff --git a/packages/InputDevices/res/values-mr/strings.xml b/packages/InputDevices/res/values-mr/strings.xml
index da6caab3842e..d8788c97b90c 100644
--- a/packages/InputDevices/res/values-mr/strings.xml
+++ b/packages/InputDevices/res/values-mr/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"स्विस जर्मन"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"बेल्जियन"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"बल्गेरियन"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"बल्गेरियन, फोनेटिक"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"इटालियन"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"डॅनिश"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"नॉर्वेजियन"</string>
diff --git a/packages/InputDevices/res/values-ms/strings.xml b/packages/InputDevices/res/values-ms/strings.xml
index 975024ba1cdf..8bc9b2a73cb2 100644
--- a/packages/InputDevices/res/values-ms/strings.xml
+++ b/packages/InputDevices/res/values-ms/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Jerman Switzerland"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Bahasa Belgium"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bahasa Bulgaria"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bahasa Bulgaria, Fonetik"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Bahasa Itali"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Bahasa Denmark"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Bahasa Norway"</string>
diff --git a/packages/InputDevices/res/values-my/strings.xml b/packages/InputDevices/res/values-my/strings.xml
index 5484d9d2a2e8..26720576ee91 100644
--- a/packages/InputDevices/res/values-my/strings.xml
+++ b/packages/InputDevices/res/values-my/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ဆွစ် ဂျာမန်"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ဘယ်လ်ဂျီယန်"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ဘူဂေးရီယန်း"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ဘူလ်ဂေးရီးယား အသံထွက်"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"အီတာလီယန်"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ဒိန်းမတ်"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"နောဝေဂျီယန်"</string>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index 54840338b966..83b87e5dd45e 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Sveitsisk standardtysk"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisk"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarsk"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarsk, fonetisk"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiensk"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dansk"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norsk"</string>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index e000a30f9cf9..6e5849013fe7 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Zwitsers Duits"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgisch"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgaars"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgaars, fonetisch"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiaans"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Deens"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Noors"</string>
diff --git a/packages/InputDevices/res/values-or/strings.xml b/packages/InputDevices/res/values-or/strings.xml
index 6185ff77695d..aa16151752e6 100644
--- a/packages/InputDevices/res/values-or/strings.xml
+++ b/packages/InputDevices/res/values-or/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ସୁଇସ୍ ଜର୍ମାନ୍‍"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ବେଲ୍‍ଜିଆନ୍‍"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ବୁଲଗାରିଆନ୍‍"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ବୁଲଗେରିଆନ୍, ଫୋନେଟିକ୍"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ଇଟାଲିୟାନ୍‌"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ଡାନିଶ୍‍"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ନରୱେଜିଆନ୍"</string>
diff --git a/packages/InputDevices/res/values-pa/strings.xml b/packages/InputDevices/res/values-pa/strings.xml
index 97cf28bbc66c..7e5a03cde986 100644
--- a/packages/InputDevices/res/values-pa/strings.xml
+++ b/packages/InputDevices/res/values-pa/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ਸਵਿਸ ਜਰਮਨ"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"ਬੈਲਜੀਅਨ"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"ਬਲਗੇਰੀਅਨ"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ਬਲਗੇਰੀਅਨ, ਧੁਨੀਆਤਮਿਕ"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ਇਤਾਲਵੀ"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ਡੈਨਿਸ਼"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"ਨਾਰਵੇਜੀਅਨ"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 61819b624112..51755e2b2b52 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Niemiecki (Szwajcaria)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgijski"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bułgarski"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bułgarski (znaki fonetyczne)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Włoski"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Duński"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norweski"</string>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index 665a1c7632f1..128868856f5a 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão suíço"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 1ccc64409452..89bb3e376678 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão (Suíça)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index 665a1c7632f1..128868856f5a 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Alemão suíço"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belga"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Búlgaro"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Búlgaro, fonético"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Dinamarquês"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norueguês"</string>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index e0b488585c78..f7ff2504f31f 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Germană (Elveția)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiană"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgară"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgară fonetică"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italiană"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Daneză"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegiană"</string>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 41ccf1a4f689..0cb4f34d4ab1 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"немецкий (Швейцария)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"нидерландский (Бельгия)"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"болгарский"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"болгарский (фонетическая)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"итальянский"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"датский"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвежский"</string>
diff --git a/packages/InputDevices/res/values-si/strings.xml b/packages/InputDevices/res/values-si/strings.xml
index 4d355d73e985..eb3c44678db2 100644
--- a/packages/InputDevices/res/values-si/strings.xml
+++ b/packages/InputDevices/res/values-si/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"ස්විස් ජර්මන්"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"බෙල්ගියන්"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"බල්ගේරියානු"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"බල්ගේරියානු, ශබ්දිම"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ඉතාලි"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ඩෙන්මාර්ක"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"නෝර්වීජියානු"</string>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index c7ff2fd5d994..e7e15b0cbd00 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švajčiarske (nemčina)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgické"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bulharské"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulharská fonetická klávesnica"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"talianske"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"dánske"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"nórske"</string>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 68741b42e880..f4d1e5732fc5 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švicarska nemška"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bolgarska"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"bolgarščina (fonetična)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanska"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index 2f68903c4e2d..e3a20438f34a 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"швајцарско немачка"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"белгијска"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"бугарска"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"бугарска фонетска"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"италијанска"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"данска"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвешка"</string>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index b465fa64ce82..097ada40be63 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tyskt (Schweiz)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiskt"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgariskt"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgariska (fonetiskt)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italienskt"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danskt"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norskt"</string>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index 794d907f006d..325796232d76 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Kijerumani cha Uswisi"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Kibelgiji"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Kibulgaria"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Kibulgaria, Fonetiki"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Kiitaliano"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Kidenmarki"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Kinorwei"</string>
diff --git a/packages/InputDevices/res/values-te/strings.xml b/packages/InputDevices/res/values-te/strings.xml
index d40c3e0d5d9f..c0253e528684 100644
--- a/packages/InputDevices/res/values-te/strings.xml
+++ b/packages/InputDevices/res/values-te/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"స్విస్ జర్మన్"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"బెల్జియన్"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"బల్గేరియన్"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"బల్గేరియన్, ఫోనెటిక్"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"ఇటాలియన్"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"డేనిష్"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"నార్వేజియన్"</string>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 59136506abe0..c8e0e62f6e18 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"เยอรมันสวิส"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"เบลเยียม"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"บัลแกเรีย"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"ภาษาบัลแกเรีย ตามการออกเสียง"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"อิตาลี"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"เดนมาร์ก"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"นอร์เวย์"</string>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index a89cea59b30f..f093abb9a708 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"İsviçre Almancası"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belçika dili"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bulgarca"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bulgarca, Fonetik"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"İtalyanca"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Danca"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norveççe"</string>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index 4b37ca954d37..d9b58d21c14f 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"німецька (Швейцарія)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"бельгійська"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"болгарська"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Болгарська (фонетична)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"італійська"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"данська"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"норвезька"</string>
diff --git a/packages/InputDevices/res/values-ur/strings.xml b/packages/InputDevices/res/values-ur/strings.xml
index ca42086b8811..2bff7ed2f234 100644
--- a/packages/InputDevices/res/values-ur/strings.xml
+++ b/packages/InputDevices/res/values-ur/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"سوئس جرمن"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"بیلجیئن"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"بلغاریائی"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"بلغاریائی، فونیٹک"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"اطالوی"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"ڈینش"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"نارویجین"</string>
diff --git a/packages/InputDevices/res/values-uz/strings.xml b/packages/InputDevices/res/values-uz/strings.xml
index 77a06b5a4d79..9245aebd22ba 100644
--- a/packages/InputDevices/res/values-uz/strings.xml
+++ b/packages/InputDevices/res/values-uz/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Nemis (Shveytsariya)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Belgiyancha"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Bolgarcha"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Bolgar, fonetik"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Italyancha"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Datcha"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Norvegcha"</string>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index fd570efe8693..1b42ece3deed 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Tiếng Đức Thụy Sĩ"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Tiếng Bỉ"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Tiếng Bungary"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Tiếng Bulgaria, Ngữ âm"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Tiếng Ý"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Tiếng Đan Mạch"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Tiếng Na Uy"</string>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index afc373acd61f..aa75605b5abd 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"瑞士德语"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利时语"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亚语"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亚语,注音"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"意大利语"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麦语"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威语"</string>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index 775fa2acfcec..dc824b97369d 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"德文(瑞士)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利時文"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亞文"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亞文 (拼音)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"意大利文"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麥文"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威文"</string>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index b4a059cbeb1f..c2714da0c3d9 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"德文 (瑞士)"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"比利時式"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"保加利亞文"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"保加利亞文 (拼音)"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"義大利文"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"丹麥文"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"挪威文"</string>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 0a2499ad8967..3af1da1ac694 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -19,8 +19,7 @@
<string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"Isi-Swiss German"</string>
<string name="keyboard_layout_belgian" msgid="2011984572838651558">"Isi-Belgian"</string>
<string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"Isi-Bulgarian"</string>
- <!-- no translation found for keyboard_layout_bulgarian_phonetic (7568914730360106653) -->
- <skip />
+ <string name="keyboard_layout_bulgarian_phonetic" msgid="7568914730360106653">"Isi-Bulgarian, Ifonetiki"</string>
<string name="keyboard_layout_italian" msgid="6497079660449781213">"Isi-Italian"</string>
<string name="keyboard_layout_danish" msgid="8036432066627127851">"Isi-Danish"</string>
<string name="keyboard_layout_norwegian" msgid="9090097917011040937">"Isi-Norwegian"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 2696f5a01785..a279872a088e 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -55,7 +55,7 @@
</string-array>
<string-array name="hdcp_checking_summaries">
<item msgid="4045840870658484038">"Երբեք չօգտագործել HDCP ստուգումը"</item>
- <item msgid="8254225038262324761">"Օգտագործել HDCP-ը` միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
+ <item msgid="8254225038262324761">"Օգտագործել HDCP-ը՝ միայն DRM-ի բովանդակությունը ստուգելու համար"</item>
<item msgid="6421717003037072581">"Միշտ օգտագործել HDCP ստուգումը"</item>
</string-array>
<string-array name="bt_hci_snoop_log_entries">
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index ffd95a45b61e..e434cac36b34 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -343,7 +343,7 @@
<string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"Թարմացվելիս ընդգծել սարքաշարի ծածկույթները կանաչ գույնով"</string>
<string name="debug_hw_overdraw" msgid="8944851091008756796">"Վրիպազերծել GPU գերազանցումները"</string>
<string name="disable_overlays" msgid="4206590799671557143">"Կասեցնել HW վրադրումները"</string>
- <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն` էկրանի կազմման համար"</string>
+ <string name="disable_overlays_summary" msgid="1954852414363338166">"Միշտ օգտագործել GPU-ն՝ էկրանի կազմման համար"</string>
<string name="simulate_color_space" msgid="1206503300335835151">"Նմանակել գունատարածքը"</string>
<string name="enable_opengl_traces_title" msgid="4638773318659125196">"Ակտիվացնել OpenGL հետքերը"</string>
<string name="usb_audio_disable_routing" msgid="3367656923544254975">"Անջատել USB աուդիո երթուղումը"</string>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index bcd2ff71b57f..4db61b02e8e9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -175,6 +175,8 @@ public class SecureSettings {
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
Settings.Secure.PANIC_GESTURE_ENABLED,
Settings.Secure.PANIC_SOUND_ENABLED,
- Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED
+ Settings.Secure.ADAPTIVE_CONNECTIVITY_ENABLED,
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 3630f257f583..1fde40c37d9c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -264,5 +264,8 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.PANIC_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.PANIC_SOUND_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ADAPTIVE_CONNECTIVITY_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(
+ Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS, NONE_NEGATIVE_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index e7ec8b4e1f65..bc6660184fe3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1875,6 +1875,15 @@ class SettingsProtoDumpUtil {
SecureSettingsProto.Assist.GESTURE_SETUP_COMPLETE);
p.end(assistToken);
+ final long assistHandlesToken = p.start(SecureSettingsProto.ASSIST_HANDLES);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ SecureSettingsProto.AssistHandles.LEARNING_TIME_ELAPSED_MILLIS);
+ dumpSetting(s, p,
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+ SecureSettingsProto.AssistHandles.LEARNING_EVENT_COUNT);
+ p.end(assistHandlesToken);
+
final long autofillToken = p.start(SecureSettingsProto.AUTOFILL);
dumpSetting(s, p,
Settings.Secure.AUTOFILL_SERVICE,
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index d69f3d620d48..504e18a1488e 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -587,15 +587,19 @@ public final class RingtonePickerActivity extends AlertActivity implements
}
private Uri getCurrentlySelectedRingtoneUri() {
- if (getCheckedItem() == mDefaultRingtonePos) {
- // Use the default Uri that they originally gave us.
- return mUriForDefaultItem;
- } else if (getCheckedItem() == mSilentPos) {
- // Use a null Uri for the 'Silent' item.
- return null;
- } else {
- return mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(getCheckedItem()));
- }
+ if (getCheckedItem() == POS_UNKNOWN) {
+ // When the getCheckItem is POS_UNKNOWN, it is not the case we expected.
+ // We return null for this case.
+ return null;
+ } else if (getCheckedItem() == mDefaultRingtonePos) {
+ // Use the default Uri that they originally gave us.
+ return mUriForDefaultItem;
+ } else if (getCheckedItem() == mSilentPos) {
+ // Use a null Uri for the 'Silent' item.
+ return null;
+ } else {
+ return mRingtoneManager.getRingtoneUri(getRingtoneManagerPosition(getCheckedItem()));
+ }
}
private void saveAnyPlayingRingtone() {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a1b9dcd9c028..cf78a131d6fb 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -776,6 +776,7 @@
android:exported="true">
<intent-filter>
<action android:name="com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG" />
+ <action android:name="com.android.systemui.action.DISMISS_MEDIA_OUTPUT_DIALOG" />
</intent-filter>
</receiver>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 24b5c23a6732..52b7fab768c5 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -100,7 +100,7 @@
<string name="kg_pin_accepted" msgid="1625501841604389716">"កូដត្រូវ​បានទទួល​យក!"</string>
<string name="keyguard_carrier_default" msgid="6359808469637388586">"គ្មាន​សេវា​ទេ។"</string>
<string name="accessibility_ime_switch_button" msgid="9082358310194861329">"ប្ដូរ​វិធី​បញ្ចូល"</string>
- <string name="airplane_mode" msgid="2528005343938497866">"មុខងារ​ពេល​ជិះ​យន្តហោះ"</string>
+ <string name="airplane_mode" msgid="2528005343938497866">"​ពេល​ជិះ​យន្តហោះ"</string>
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 0229e6e9d4dd..73beefc9da83 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -32,7 +32,7 @@
android:id="@+id/header_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingEnd="16dp"/>
+ android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"/>
<LinearLayout
android:layout_width="match_parent"
@@ -70,36 +70,14 @@
android:id="@+id/device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
android:orientation="vertical">
- <View
- android:layout_width="match_parent"
- android:layout_height="12dp"/>
-
- <include
- layout="@layout/media_output_list_item"
- android:id="@+id/group_item_controller"
- android:visibility="gone"/>
-
- <View
- android:id="@+id/group_item_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider"
- android:visibility="gone"/>
-
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_result"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"/>
-
- <View
- android:id="@+id/list_bottom_padding"
- android:layout_width="match_parent"
- android:layout_height="12dp"/>
</LinearLayout>
<View
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index fd89c0bf39dd..10ad8291636e 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:clipChildren="false"
- android:paddingTop="11dp"
+ android:paddingTop="@dimen/notification_guts_header_top_padding"
android:clipToPadding="true">
<ImageView
android:id="@+id/conversation_icon"
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 92b3ff335cba..0a33d5e4429b 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -30,10 +30,11 @@
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_guts_conversation_header_height"
+ android:layout_height="wrap_content"
android:gravity="center_vertical"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:paddingTop="@dimen/notification_guts_header_top_padding"
+ android:clipToPadding="true">
<ImageView
android:id="@+id/pkg_icon"
android:layout_width="@dimen/notification_guts_conversation_icon_size"
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index c353d089895c..af66f8ba4cd6 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -30,10 +30,11 @@
<LinearLayout
android:id="@+id/header"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_guts_conversation_header_height"
+ android:layout_height="wrap_content"
android:gravity="center_vertical"
android:clipChildren="false"
- android:clipToPadding="false">
+ android:paddingTop="@dimen/notification_guts_header_top_padding"
+ android:clipToPadding="true">
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/notification_guts_conversation_icon_size"
diff --git a/packages/SystemUI/res/layout/window_magnifier_view.xml b/packages/SystemUI/res/layout/window_magnifier_view.xml
index 6ced97836358..efd24c7d9d4f 100644
--- a/packages/SystemUI/res/layout/window_magnifier_view.xml
+++ b/packages/SystemUI/res/layout/window_magnifier_view.xml
@@ -17,24 +17,26 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="wrap_content">
-
+ android:layout_height="wrap_content"
+ android:screenReaderFocusable="true">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/magnification_outer_border_margin"
+ android:importantForAccessibility="no"
android:background="@android:color/black"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/magnification_inner_border_margin"
+ android:importantForAccessibility="no"
android:background="@color/magnification_border_color"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:importantForAccessibility="noHideDescendants">
<View
android:id="@+id/left_handle"
@@ -76,6 +78,7 @@
android:layout_margin="@dimen/magnification_outer_border_margin"
android:layout_gravity="right|bottom"
android:scaleType="center"
+ android:importantForAccessibility="no"
android:src="@drawable/ic_move_magnification"/>
</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 556c39091cce..72dfe74b2fde 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Wys laeprioriteit-kennisgewingikone"</string>
<string name="other" msgid="429768510980739978">"Ander"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"verwyder teël"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"voeg teël aan einde by"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Skuif teël"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Voeg teël by"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Skuif na <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Voeg by posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kitsinstellingswysiger."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-kennisgewing: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Maak instellings oop."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c8462976528c..0ec236de8867 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"አነስተኛ ቅድሚያ ያላቸው የማሳወቂያ አዶዎችን አሳይ"</string>
<string name="other" msgid="429768510980739978">"ሌላ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ሰቅ አስወግድ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ሰቅ መጨረሻው ላይ አክል"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ሰቁን ውሰድ"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ሰቅ ያክሉ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ውሰድ"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ቦታ አክል"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"የ<xliff:g id="POSITION">%1$d</xliff:g> አቀማመጥ"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"የፈጣን ቅንብሮች አርታዒ።"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"የ<xliff:g id="ID_1">%1$s</xliff:g> ማሳወቂያ፦ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ቅንብሮችን ክፈት።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 785f8feb551a..e1d195028dcb 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -899,20 +899,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"إظهار رموز الإشعارات ذات الأولوية المنخفضة"</string>
<string name="other" msgid="429768510980739978">"غير ذلك"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"إزالة البطاقة"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"إضافة بطاقة إلى النهاية"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"نقل البطاقة"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"إضافة بطاقة"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"الانتقال إلى <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"الإضافة إلى الموضع <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"الموضع: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"برنامج تعديل الإعدادات السريعة."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"إشعار <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"فتح الإعدادات."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 059c4bca8181..61ba6dc1265c 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"কম গুৰুত্বপূৰ্ণ জাননীৰ আইকনসমূহ দেখুৱাওক"</string>
<string name="other" msgid="429768510980739978">"অন্যান্য"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল আঁতৰাবলৈ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"টাইল শেষত যোগ দিবলৈ"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল স্থানান্তৰ কৰক"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"টাইল যোগ দিয়ক"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰলৈ স্থানান্তৰ কৰক"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থানত যোগ দিয়ক"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থান"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিংসমূহৰ সম্পাদক।"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> জাননী: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ছেটিংসমূহ খোলক।"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 2381d3330730..bee0e5fdca54 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Aşağı prioritet bildiriş işarələrini göstərin"</string>
<string name="other" msgid="429768510980739978">"Digər"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"lövhəni silin"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"sona lövhə əlavə edin"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Lövhəni köçürün"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lövhə əlavə edin"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə köçürün"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə əlavə edin"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sürətli ayarlar redaktoru."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildiriş: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ayarları açın."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 55abfda98bc8..5966356d1e66 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obaveštenja niskog prioriteta"</string>
<string name="other" msgid="429768510980739978">"Drugo"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklonili pločicu"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodali pločicu na kraj"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premestite pločicu"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajte pločicu"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premestite na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajte na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač za Brza podešavanja."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Obaveštenja za <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvori Podešavanja."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 47f9861f640b..cedc3753da42 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Паказваць значкі апавяшчэнняў з нізкім прыярытэтам"</string>
<string name="other" msgid="429768510980739978">"Іншае"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"выдаліць плітку"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"дадаць плітку ў канец"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перамясціць плітку"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Дадаць плітку"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перамясціць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Дадаць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Пазіцыя <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Рэдактар хуткіх налад."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Апавяшчэнне <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Адкрыць налады."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index efe12673fe78..14088404e81b 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Показване на иконите за известията с нисък приоритет"</string>
<string name="other" msgid="429768510980739978">"Друго"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"премахване на панел"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"добавяне на панел в края"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместване на панел"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавяне на панел"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместване към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор за бързи настройки."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Известие от <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отваряне на настройките."</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 811a971ab02b..41a2671466df 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obavještenja niskog prioriteta"</string>
<string name="other" msgid="429768510980739978">"Ostalo"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodavanje kartice na kraj"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pomjeranje kartice"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pomjeranje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivanje brzih postavki"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> obavještenje: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvori postavke."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 793c44b4544b..783f7877e230 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -92,10 +92,10 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processant gravació de pantalla"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Vols iniciar la gravació?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"Quan graves contingut, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou les contrasenyes, la informació de pagament, les fotos, els missatges i l\'àudio."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"Durant la gravació, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou contrasenyes, informació de pagament, fotos, missatges i àudio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Grava l\'àudio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Àudio del dispositiu"</string>
- <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sons del dispositiu, com ara la música, les trucades i els sons de trucada"</string>
+ <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"So del dispositiu, com ara música, trucades i sons de trucada"</string>
<string name="screenrecord_mic_label" msgid="2111264835791332350">"Micròfon"</string>
<string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Àudio del dispositiu i micròfon"</string>
<string name="screenrecord_start" msgid="330991441575775004">"Inicia"</string>
@@ -387,7 +387,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"La Wi‑Fi no està connectada"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTOMÀTICA"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix els colors"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Inverteix colors"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Mode de correcció de color"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Més opcions"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostra les icones de notificació amb prioritat baixa"</string>
<string name="other" msgid="429768510980739978">"Altres"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"suprimir el mosaic"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"afegir una targeta al final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mou la targeta"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Afegeix una targeta"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mou a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuració ràpida."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificació de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Obre la configuració."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1d9238932283..f2e8a3f908f3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for notifikationer med lav prioritet"</string>
<string name="other" msgid="429768510980739978">"Andet"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern kortet"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj kortet til slutningen"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt kortet"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj et kort"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flyt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åbn Indstillinger."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5976a1c95362..887aad5d9aa6 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Symbole für Benachrichtigungen mit einer niedrigen Priorität anzeigen"</string>
<string name="other" msgid="429768510980739978">"Sonstiges"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"die Kachel zu entfernen"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"die Kachel am Ende hinzuzufügen"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kachel verschieben"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Kachel hinzufügen"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Auf Position <xliff:g id="POSITION">%1$d</xliff:g> verschieben"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Zur Position <xliff:g id="POSITION">%1$d</xliff:g> hinzufügen"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor für Schnelleinstellungen."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Benachrichtigung von <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Einstellungen öffnen."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1eae5d4a12f9..1b912c7a6ed9 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Εμφάνιση εικονιδίων ειδοποιήσεων χαμηλής προτεραιότητας"</string>
<string name="other" msgid="429768510980739978">"Άλλο"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"κατάργηση πλακιδίου"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"προσθήκη πλακιδίου στο τέλος"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Μετακίνηση πλακιδίου"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Προσθήκη πλακιδίου"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Μετακίνηση στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Προσθήκη στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Ειδοποίηση <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Άνοιγμα ρυθμίσεων."</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 4ea0341f8c39..065c17bec41a 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -92,7 +92,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3916e58ba076..1cc662521645 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -92,7 +92,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 4ea0341f8c39..065c17bec41a 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -92,7 +92,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 4ea0341f8c39..065c17bec41a 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -92,7 +92,7 @@
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Processing screen recording"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
- <string name="screenrecord_description" msgid="1123231719680353736">"While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+ <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
<string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
<string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
<string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b1ee41f4c53c..dfd42c3ea54f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar íconos de notificaciones con prioridad baja"</string>
<string name="other" msgid="429768510980739978">"Otros"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Quitar tarjeta"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"Agregar tarjeta al final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover la tarjeta"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Agregar tarjeta"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de Configuración rápida"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir Configuración"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 7e5361b4f70c..20b50abd5b08 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconos de notificaciones con prioridad baja"</string>
<string name="other" msgid="429768510980739978">"Otros"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar icono"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"añadir icono al final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover icono"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Añadir icono"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Añadir a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de ajustes rápidos."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir ajustes."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 78de793517f4..ced06044f331 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Kuva madala prioriteediga märguande ikoonid"</string>
<string name="other" msgid="429768510980739978">"Muu"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"paani eemaldamiseks"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"paani lõppu lisamiseks"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Teisalda paan"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisa paan"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Teisaldamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Asend <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kiirseadete redigeerija."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Teenuse <xliff:g id="ID_1">%1$s</xliff:g> märguanne: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ava seaded."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b5d84447271a..c1ab20c9ebb6 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Erakutsi lehentasun txikiko jakinarazpenen ikonoak"</string>
<string name="other" msgid="429768510980739978">"Beste bat"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"kendu lauza"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"gehitu lauza amaieran"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Aldatu tokiz lauza"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Gehitu lauza"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Eraman <xliff:g id="POSITION">%1$d</xliff:g>garren kokapenera"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Gehitu <xliff:g id="POSITION">%1$d</xliff:g>garren kokapenean"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kokapena: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ezarpen bizkorren editorea."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> zerbitzuaren jakinarazpena: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ireki ezarpenak."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d453f91da504..f6cf179d7d00 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"نمایش نمادهای اعلان کم‌اهمیت"</string>
<string name="other" msgid="429768510980739978">"موارد دیگر"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"برداشتن کاشی"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"افزودن کاشی به انتها"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"انتقال کاشی"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"افزودن کاشی"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"انتقال به <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ویرایشگر تنظیمات سریع."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"اعلان <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"باز کردن تنظیمات."</string>
@@ -967,7 +960,7 @@
<string name="slice_permission_text_2" msgid="6758906940360746983">"- می‌تواند در <xliff:g id="APP">%1$s</xliff:g> اقدام انجام دهد"</string>
<string name="slice_permission_checkbox" msgid="4242888137592298523">"به <xliff:g id="APP">%1$s</xliff:g> اجازه داده شود تکه‌هایی از برنامه‌ها نشان دهد"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"مجاز"</string>
- <string name="slice_permission_deny" msgid="6870256451658176895">"رد کردن"</string>
+ <string name="slice_permission_deny" msgid="6870256451658176895">"مجاز نبودن"</string>
<string name="auto_saver_title" msgid="6873691178754086596">"برای زمان‌بندی «بهینه‌سازی باتری» ضربه بزنید"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"وقتی باتری روبه‌اتمام است، بهینه‌سازی باتری را روشن کنید"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"نه متشکرم"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index dde2449d8894..3d9a6dbee1f9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -379,7 +379,7 @@
<string name="quick_settings_wifi_on_label" msgid="2489928193654318511">"Wi-Fi on käytössä"</string>
<string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ei Wi-Fi-verkkoja käytettävissä"</string>
<string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Otetaan käyttöön…"</string>
- <string name="quick_settings_cast_title" msgid="2279220930629235211">"Näytön suoratoisto"</string>
+ <string name="quick_settings_cast_title" msgid="2279220930629235211">"Näytön striimaus"</string>
<string name="quick_settings_casting" msgid="1435880708719268055">"Lähetetään"</string>
<string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Nimetön laite"</string>
<string name="quick_settings_cast_device_default_description" msgid="2580520859212250265">"Valmis lähetystä varten"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Näytä vähemmän tärkeät ilmoituskuvakkeet"</string>
<string name="other" msgid="429768510980739978">"Muu"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"poista kiekko"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"lisää kiekko loppuun"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Siirrä kiekkoa"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lisää kiekko"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Siirrä paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisää paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Pika-asetusten muokkausnäkymä"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Ilmoitus kohteesta <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Avaa asetukset."</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index aba2d8fd389a..9075a69b2ed8 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconas das notificacións que teñan baixa prioridade"</string>
<string name="other" msgid="429768510980739978">"Outros"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar tarxeta"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"engadir tarxeta ao final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover tarxeta"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Engadir tarxeta"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover a <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engadir á posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuración rápida."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificación de <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configuración."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 1acef350034a..e8b446063922 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"ઓછી પ્રાધાન્યતાનું નોટિફિકેશન આઇકન બતાવો"</string>
<string name="other" msgid="429768510980739978">"અન્ય"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ટાઇલ કાઢી નાખો"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ટાઇલને અંતે ઉમેરો"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ટાઇલ ખસેડો"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ટાઇલ ઉમેરો"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> પર ખસેડો"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"જગ્યા પર <xliff:g id="POSITION">%1$d</xliff:g> ઉમેરો"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ્સ સંપાદક."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> નોટિફિકેશન: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"સેટિંગ્સ ખોલો."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9b3f99748375..649299b1cd7d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obavijesti niskog prioriteta"</string>
<string name="other" msgid="429768510980739978">"Ostalo"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodavanje kartice na kraj"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premještanje kartice"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodavanje kartice"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premještanje u prostoriju <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač brzih postavki."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> obavijest: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvaranje postavki."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 7f4fa9d0acd3..f658bb76c649 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Alacsony prioritású értesítési ikonok mutatása"</string>
<string name="other" msgid="429768510980739978">"Egyéb"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"mozaik eltávolításához"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"mozaiknak a végéhez való hozzáadásához"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mozaik áthelyezése"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Mozaik hozzáadása"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Áthelyezés ide: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Gyorsbeállítások szerkesztője"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-értesítések: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Beállítások megnyitása."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 70cbf493feca..28c79fbc8852 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Ցուցադրել ցածր առաջնահերթության ծանուցումների պատկերակները"</string>
<string name="other" msgid="429768510980739978">"Այլ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"հեռացնել սալիկը"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ավելացնել սալիկ վերջում"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Տեղափոխել սալիկը"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ավելացնել սալիկ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Տեղափոխել դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Արագ կարգավորումների խմբագրիչ:"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ծանուցում՝ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Բացել կարգավորումները:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dc0a5128b808..12f42e84c3db 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -862,7 +862,7 @@
<string name="left_icon" msgid="5036278531966897006">"Ikon kiri"</string>
<string name="right_icon" msgid="1103955040645237425">"Ikon kanan"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Tahan dan tarik untuk menambahkan kartu"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan tarik untuk mengatur ulang kartu"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tahan dan tarik untuk menata ulang kartu"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Tarik ke sini untuk menghapus"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Anda membutuhkan setidaknya <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> kartu"</string>
<string name="qs_edit" msgid="5583565172803472437">"Edit"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Tampilkan ikon notifikasi prioritas rendah"</string>
<string name="other" msgid="429768510980739978">"Lainnya"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"menghapus kartu"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"menambahkan kartu ke akhir"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pindahkan kartu"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan kartu"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pindahkan ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan ke posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor setelan cepat."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notifikasi <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buka setelan."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index f79796b6276d..1f8f2aa2fc27 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -861,10 +861,10 @@
<string name="right_keycode" msgid="2480715509844798438">"Lykiltákn til hægri"</string>
<string name="left_icon" msgid="5036278531966897006">"Tákn til vinstri"</string>
<string name="right_icon" msgid="1103955040645237425">"Tákn til hægri"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Haltu inni og dragðu til að bæta við reitum"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Haltu inni og dragðu til að bæta við flísum"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Haltu og dragðu til að endurraða flísum"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Dragðu hingað til að fjarlægja"</string>
- <string name="drag_to_remove_disabled" msgid="933046987838658850">"Reitirnir mega ekki vera færri en <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
+ <string name="drag_to_remove_disabled" msgid="933046987838658850">"Flísarnar mega ekki vera færri en <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
<string name="qs_edit" msgid="5583565172803472437">"Breyta"</string>
<string name="tuner_time" msgid="2450785840990529997">"Tími"</string>
<string-array name="clock_options">
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Sýna tákn fyrir tilkynningar með litlum forgangi"</string>
<string name="other" msgid="429768510980739978">"Annað"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjarlægja reit"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"bæta reit við aftast"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Færa reit"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Bæta reit við"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Færa í <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bæta við í stöðu <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Staða <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Flýtistillingaritill."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> tilkynning: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Opna stillingar."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3b99dc2e1f6e..eb76a4b58fcd 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostra icone di notifiche con priorità bassa"</string>
<string name="other" msgid="429768510980739978">"Altro"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"rimuovere il riquadro"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"aggiungere il riquadro alla fine"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Sposta riquadro"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Aggiungi riquadro"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Sposta nella posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor di impostazioni rapide."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notifica di <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Apri le impostazioni."</string>
@@ -975,7 +968,7 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"Il Risparmio energetico verrà attivato automaticamente quando la carica della batteria sarà inferiore a <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Impostazioni"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
- <string name="heap_dump_tile_name" msgid="2464189856478823046">"Esegui dump heap SysUI"</string>
+ <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump heap SysUI"</string>
<string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"L\'app <xliff:g id="APP">%1$s</xliff:g> sta usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3bb8ea5fe1dd..31e6befca5ff 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"הצגת סמלי התראות בעדיפות נמוכה"</string>
<string name="other" msgid="429768510980739978">"אחר"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"הסרת האריח"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"הוספת האריח לקצה"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"הזזת האריח"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"הוספת אריח"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"העברה אל <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"הוספה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"עורך הגדרות מהירות."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"התראות <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"פתיחת הגדרות."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2c55569bb96a..b358f3d866dc 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"優先度の低い通知アイコンを表示"</string>
<string name="other" msgid="429768510980739978">"その他"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"タイルを削除"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"タイルを最後に追加"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"タイルを移動"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"タイルを追加"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> に移動"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に追加"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"クイック設定エディタ"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> の通知: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"設定を開きます。"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index ca5b7da19247..4e85d608a72b 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"დაბალი პრიორიტეტის მქონე შეტყობინებების ხატულების ჩვენება"</string>
<string name="other" msgid="429768510980739978">"სხვა"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"მოზაიკის ფილის წაშლა"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ფილის ბოლოში დამატება"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"მოზაიკის გადატანა"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"მოზაიკის დამატება"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"გადატანა <xliff:g id="POSITION">%1$d</xliff:g>-ზე"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"სწრაფი პარამეტრების რედაქტორი."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> შეტყობინება: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"პარამეტრების გახსნა."</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a4bf498edfff..f17210602b83 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -865,7 +865,7 @@
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердің ретін өзгерту үшін оларды басып тұрып сүйреңіз"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Керексіздерін осы жерге сүйреңіз"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Кемінде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> бөлшек қажет."</string>
- <string name="qs_edit" msgid="5583565172803472437">"Өңдеу"</string>
+ <string name="qs_edit" msgid="5583565172803472437">"Өзгерту"</string>
<string name="tuner_time" msgid="2450785840990529997">"Уақыт"</string>
<string-array name="clock_options">
<item msgid="3986445361435142273">"Сағаттарды, минуттарды және секундтарды көрсету"</item>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Маңызды емес хабарландыру белгішелерін көрсету"</string>
<string name="other" msgid="429768510980739978">"Басқа"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"бөлшекті өшіру"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"бөлшекті соңына қосу"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Бөлшекті жылжыту"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Бөлшек қосу"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> орнына жылжыту"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> орнына қосу"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> орны"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Жылдам параметрлер өңдегіші."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> хабарландыруы: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Параметрлерді ашу."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 7eaa3039947a..b126a11d1310 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"បង្ហាញ​រូប​ការជូនដំណឹង​ដែលមានអាទិភាពទាប"</string>
<string name="other" msgid="429768510980739978">"ផ្សេងៗ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ដកប្រអប់ចេញ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"បញ្ចូល​ប្រអប់ទៅ​ខាងចុង"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ផ្លាស់ទី​ប្រអប់"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"បញ្ចូល​ប្រអប់"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ផ្លាស់​ទីទៅ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"បញ្ចូលទៅ​ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"កម្មវិធីកែការកំណត់រហ័ស"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ការជូនដំណឹង៖ <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"បើកការកំណត់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 79f845290365..475677be3845 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -387,7 +387,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"ಸ್ವಯಂ"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"ಬಣ್ಣಗಳನ್ನು ಇನ್ವರ್ಟ್ ಮಾಡಿ"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"ಬಣ್ಣ ತಿದ್ದುಪಡಿ ಮೋಡ್"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"ಕಡಿಮೆ-ಆದ್ಯತೆ ಸೂಚನೆಯ ಐಕಾನ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="other" msgid="429768510980739978">"ಇತರ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ಟೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ಕೊನೆಯಲ್ಲಿ ಟೈಲ್ ಸೇರಿಸಿ"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ಟೈಲ್ ಸರಿಸಿ"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ಟೈಲ್ ಸೇರಿಸಿ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ಇಲ್ಲಿಗೆ ಸರಿಸಿ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಎಡಿಟರ್."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ಅಧಿಸೂಚನೆ: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 6a755e52f058..ac7f04e77586 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -371,7 +371,7 @@
<string name="quick_settings_time_label" msgid="3352680970557509303">"시간"</string>
<string name="quick_settings_user_label" msgid="1253515509432672496">"나"</string>
<string name="quick_settings_user_title" msgid="8673045967216204537">"사용자"</string>
- <string name="quick_settings_user_new_user" msgid="3347905871336069666">"새 사용자"</string>
+ <string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"연결되어 있지 않음"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"네트워크가 연결되지 않음"</string>
@@ -473,7 +473,7 @@
<string name="accessibility_multi_user_switch_inactive" msgid="383168614528618402">"현재 사용자: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"프로필 표시"</string>
<string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string>
- <string name="user_new_user_name" msgid="2019166282704195789">"새 사용자"</string>
+ <string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"우선순위가 낮은 알림 아이콘 표시"</string>
<string name="other" msgid="429768510980739978">"기타"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"타일 삭제"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"끝에 타일 추가"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"타일 이동"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"타일 추가"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> 위치로 이동"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> 위치에 추가"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> 위치"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"빠른 설정 편집기"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 알림: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"설정 열기"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index a740d07f7eac..d775823b298c 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -862,7 +862,7 @@
<string name="left_icon" msgid="5036278531966897006">"¨Солго¨ сүрөтчөсү"</string>
<string name="right_icon" msgid="1103955040645237425">"¨Оңго¨ сүрөтчөсү"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Керектүү элементтерди сүйрөп келиңиз"</string>
- <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн, кармап туруп, сүйрөңүз"</string>
+ <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Элементтердин иретин өзгөртүү үчүн кармап туруп, сүйрөңүз"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Алып салуу үчүн бул жерге сүйрөңүз"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Сизге жок дегенде <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> мозаика керек"</string>
<string name="qs_edit" msgid="5583565172803472437">"Түзөтүү"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Анча маанилүү эмес билдирменин сүрөтчөлөрүн көрсөтүү"</string>
<string name="other" msgid="429768510980739978">"Башка"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"плитканы өчүрүү"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"плитканы аягына кошуу"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Плитканы жылдыруу"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Плитка кошуу"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Төмөнкүгө жылдыруу: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ыкчам жөндөөлөр түзөткүчү."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> эскертмеси: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Жөндөөлөрдү ачуу."</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1fb2ca0b0bd2..67642d3471f5 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"ສະແດງໄອຄອນການແຈ້ງເຕືອນຄວາມສຳຄັນຕ່ຳ"</string>
<string name="other" msgid="429768510980739978">"ອື່ນໆ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ລຶບແຜ່ນອອກ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ເພີ່ມແຜ່ນໃສ່ທ້າຍ"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ຍ້າຍແຜ່ນ"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ເພີ່ມແຜ່ນ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ຍ້າຍໄປ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"ການແຈ້ງເຕືອນ <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ເປີດການຕັ້ງຄ່າ."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index bd24722436dd..e17f6e490373 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Rodyti mažo prioriteto pranešimų piktogramas"</string>
<string name="other" msgid="429768510980739978">"Kita"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"pašalintumėte išklotinės elementą"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pridėtumėte išklotinės elementą gale"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Perkelti išklotinės elementą"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridėti išklotinės elementą"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Perkelkite į <xliff:g id="POSITION">%1$d</xliff:g> poziciją"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sparčiųjų nustatymų redagavimo priemonė."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"„<xliff:g id="ID_1">%1$s</xliff:g>“ pranešimas: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Atidaryti nustatymus."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index e8d9a4d8c797..96d563c61a75 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Rādīt zemas prioritātes paziņojumu ikonas"</string>
<string name="other" msgid="429768510980739978">"Citi"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"noņemt elementu"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pievienot elementu beigās"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pārvietot elementu"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pievienot elementu"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Pārvietot uz pozīciju numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pievienot elementu pozīcijā numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozīcija numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ātro iestatījumu redaktors."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> paziņojums: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Atvērt iestatījumus."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 164cb96bf046..f53147e03c84 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Прикажувај икони за известувања со низок приоритет"</string>
<string name="other" msgid="429768510980739978">"Друго"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"отстранување на плочката"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додавање на плочката на крај"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместување на плочката"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додавање плочка"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместување на <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додавање на позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уредник за брзи поставки."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Известување од <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отворете ги поставките."</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index ba379d3b7116..fc6868152dc0 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -387,7 +387,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"വൈഫൈ കണക്റ്റ് ചെയ്‌തിട്ടില്ല"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"യാന്ത്രികം"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നിറം മാറ്റുക"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"നെഗറ്റീവ് ലുക്ക്"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"വർണ്ണം ശരിയാക്കൽ മോഡ്"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"കൂടുതൽ ക്രമീകരണങ്ങൾ"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"പ്രാധാന്യം കുറഞ്ഞ അറിയിപ്പ് ചിഹ്‌നങ്ങൾ"</string>
<string name="other" msgid="429768510980739978">"മറ്റുള്ളവ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ടൈൽ നീക്കം ചെയ്യുക"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ടൈൽ, അവസാന ഭാഗത്ത് ചേർക്കുക"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ടൈൽ നീക്കുക"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ടൈൽ ചേർക്കുക"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>-ലേക്ക് നീക്കുക"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>-ൽ ചേർക്കുക"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> അറിയിപ്പ്: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ക്രമീകരണം തുറക്കുക."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 56c5ef27baec..1c82e48c9ad9 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Бага ач холбогдолтой мэдэгдлийн дүрс тэмдгийг харуулах"</string>
<string name="other" msgid="429768510980739978">"Бусад"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"хавтанг хасна уу"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"дуусгахын тулд хавтан нэмэх"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Хавтанг зөөх"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Хавтан нэмэх"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> руу зөөнө үү"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> байрлалд нэмнэ үү"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Түргэн тохиргоо засварлагч."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> мэдэгдэл: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Тохиргоог нээнэ үү."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 728065fbd5cc..b26f89f63243 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"कमी प्राधान्य सूचना आयकन दर्शवा"</string>
<string name="other" msgid="429768510980739978">"अन्य"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल काढून टाका"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"टाइल शेवटच्या स्थानावर जोडा"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल हलवा"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल जोडा"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> यावर हलवा"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> स्थानावर जोडा"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थान <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिंग्ज संपादक."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> सूचना: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"सेटिंग्ज उघडा."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 62d845c3f72a..92bc807e76cc 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Tunjukkan ikon pemberitahuan keutamaan rendah"</string>
<string name="other" msgid="429768510980739978">"Lain-lain"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alih keluar jubin"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"tambahkan jubin pada bahagian hujung"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Alihkan jubin"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tambahkan jubin"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Alih ke <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan pada kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor tetapan pantas."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Pemberitahuan <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buka tetapan."</string>
@@ -975,7 +968,7 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"Penjimat Bateri akan dihidupkan secara automatik setelah kuasa bateri kurang daripada <xliff:g id="PERCENTAGE">%d</xliff:g>%%."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Tetapan"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
- <string name="heap_dump_tile_name" msgid="2464189856478823046">"Longgok Tmbunn SysUI"</string>
+ <string name="heap_dump_tile_name" msgid="2464189856478823046">"DumpSys"</string>
<string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> sedang menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g> anda."</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index e72f16925eab..9cc9398979de 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"အရေးမကြီးသော အကြောင်းကြားချက် သင်္ကေတများ ပြရန်"</string>
<string name="other" msgid="429768510980739978">"အခြား"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"အကွက်ငယ်ကို ဖယ်ရှားရန်"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"အဆုံးတွင် အကွက်ငယ်ထည့်ရန်"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"အကွက်ငယ်ကို ရွှေ့ရန်"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"အကွက်ငယ်ကို ထည့်ရန်"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> သို့ ရွှေ့ရန်"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထားသို့ ပေါင်းထည့်ရန်"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထား"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> အကြောင်းကြားချက် − <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ဆက်တင်များကို ဖွင့်ပါ။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 41aabcb89b65..92ae68943352 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for varsler med lav prioritet"</string>
<string name="other" msgid="429768510980739978">"Annet"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjerne infobrikken"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"legge til en infobrikke på slutten"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytt infobrikken"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Legg til en infobrikke"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Legg til posisjonen <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisjon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsvindu for hurtiginnstillinger."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-varsel: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åpne innstillingene."</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0cf09d2bdd0d..1346874ed08f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकताका सूचना आइकनहरू देखाउनुहोस्"</string>
<string name="other" msgid="429768510980739978">"अन्य"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाउनुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"टाइल अन्त्यमा हाल्नुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल सार्नुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"टाइल हाल्नुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"टाइल सारेर <xliff:g id="POSITION">%1$d</xliff:g> मा लैजानुहोस्"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल यो अवस्था <xliff:g id="POSITION">%1$d</xliff:g> मा हाल्नुहोस्"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिङ सम्पादक।"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> को सूचना: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"सेटिङहरूलाई खोल्नुहोस्।"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 49e097e5a047..139b57b7c3bf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Pictogrammen voor meldingen met lage prioriteit weergeven"</string>
<string name="other" msgid="429768510980739978">"Overig"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"tegel verwijderen"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"tegel toevoegen aan einde"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Tegel verplaatsen"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tegel toevoegen"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Verplaatsen naar <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Toevoegen aan positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor voor \'Snelle instellingen\'."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-melding: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Instellingen openen."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index c3105ff55bc7..3973734f16d2 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -861,7 +861,7 @@
<string name="right_keycode" msgid="2480715509844798438">"ଡାହାଣ କୀ\'କୋଡ୍‍"</string>
<string name="left_icon" msgid="5036278531966897006">"ବାମ ଆଇକନ୍‍"</string>
<string name="right_icon" msgid="1103955040645237425">"ଡାହାଣ ଆଇକନ୍"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"ଟାଇଲ୍ ଯୋଡ଼ିବା ପାଇଁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"ଟାଇଲ୍ ଯୋଗ କରିବା ପାଇଁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"ଟାଇଲ୍‍ ପୁଣି ସଜାଇବାକୁ ଦାବିଧରି ଟାଣନ୍ତୁ"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"ବାହାର କରିବାକୁ ଏଠାକୁ ଡ୍ରାଗ୍‍ କରନ୍ତୁ"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"ଆପଣଙ୍କର ଅତିକମ୍‌ରେ <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>ଟି ଟାଇଲ୍ ଆବଶ୍ୟକ"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"କମ୍‍-ଅଗ୍ରାଧିକାର ବିଜ୍ଞପ୍ତି ଆଇକନ୍‍ ଦେଖାନ୍ତୁ"</string>
<string name="other" msgid="429768510980739978">"ଅନ୍ୟାନ୍ୟ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ଟାଇଲ୍ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ଶେଷରେ ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ଟାଇଲ୍ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>କୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ଅବସ୍ଥିତିରେ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ସେଟିଂସ୍ ଖୋଲନ୍ତୁ।"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index b12dfb3954ee..e727f48a1a3e 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"ਘੱਟ ਤਰਜੀਹ ਵਾਲੇ ਸੂਚਨਾ ਪ੍ਰਤੀਕਾਂ ਨੂੰ ਦਿਖਾਓ"</string>
<string name="other" msgid="429768510980739978">"ਹੋਰ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ਟਾਇਲ ਹਟਾਓ"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ਟਾਇਲ ਨੂੰ ਅੰਤ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ਟਾਇਲ ਨੂੰ ਲਿਜਾਓ"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> \'ਤੇ ਲਿਜਾਓ"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ਸਥਾਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ਸਥਾਨ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> ਸੂਚਨਾ: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹੋ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d195977f460b..f188aaa1ca76 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Pokazuj ikony powiadomień o niskim priorytecie"</string>
<string name="other" msgid="429768510980739978">"Inne"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"usunąć kartę"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodać kartę na końcu"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Przenieś kartę"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodaj kartę"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Przenieś do pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodaj w pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozycja <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Edytor szybkich ustawień."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Powiadomienie z aplikacji <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otwórz ustawienia."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 6f96f37bc302..8c8adae62e82 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
<string name="other" msgid="429768510980739978">"Outros"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o bloco ao final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configurações."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 93999f6b7b49..082e14ec6fc3 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -861,7 +861,7 @@
<string name="right_keycode" msgid="2480715509844798438">"Código de tecla direito"</string>
<string name="left_icon" msgid="5036278531966897006">"Ícone esquerdo"</string>
<string name="right_icon" msgid="1103955040645237425">"Ícone direito"</string>
- <string name="drag_to_add_tiles" msgid="8933270127508303672">"Toque sem soltar e arraste para adicionar mosaicos."</string>
+ <string name="drag_to_add_tiles" msgid="8933270127508303672">"Tocar sem soltar e arrastar para adicionar mosaicos"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Tocar sem soltar e arrastar para reorganizar os mosaicos"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Arrastar para aqui para remover"</string>
<string name="drag_to_remove_disabled" msgid="933046987838658850">"Necessita de, pelo menos, <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g> cartões"</string>
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de prioridade baixa"</string>
<string name="other" msgid="429768510980739978">"Outro"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o cartão"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o cartão ao final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover cartão"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar cartão"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mova para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir as definições."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 6f96f37bc302..8c8adae62e82 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
<string name="other" msgid="429768510980739978">"Outros"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adicionar o bloco ao final"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adicionar bloco"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mover para <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificação do <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Abrir configurações."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 9810cc5540cb..4128c21eaa4e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Afișați pictogramele de notificare cu prioritate redusă"</string>
<string name="other" msgid="429768510980739978">"Altele"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"eliminați cardul"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adăugați cardul la sfârșit"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mutați cardul"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adăugați un card"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mutați pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adăugați pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editorul pentru setări rapide."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notificare <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Deschideți setările."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9f43b5ac7f16..66e3ec3ba78a 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Показывать значки уведомлений с низким приоритетом"</string>
<string name="other" msgid="429768510980739978">"Другое"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"удалить кнопку быстрого доступа"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"добавить кнопку быстрого доступа в конец"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Переместить кнопку быстрого доступа"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Добавить кнопку быстрого доступа"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Переместить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор быстрых настроек."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Уведомление <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Открыть настройки."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 700f5101475c..98e8d1fd9d63 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"අඩු ප්‍රමුඛතා දැනුම්දීම් අයිකන පෙන්වන්න"</string>
<string name="other" msgid="429768510980739978">"වෙනත්"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ටයිල් ඉවත් කරන්න"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"අගට ටයිල් එක් කරන්න"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ටයිල් ගෙන යන්න"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ටයිල් එක් කරන්න"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> වෙත ගෙන යන්න"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ස්ථානයට එක් කරන්න"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> දැනුම්දීම: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"සැකසීම් විවෘත කරන්න."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 62df35aeee02..d9c6279ec42e 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Zobraziť ikony upozornení s nízkou prioritou"</string>
<string name="other" msgid="429768510980739978">"Ďalšie"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstrániť kartu"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"pridať kartu na koniec"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Presunúť kartu"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Pridať kartu"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Presunúť na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rýchlych nastavení"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Upozornenie <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Otvoriť nastavenia"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 25bdd656b56c..778938c77374 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Pokaži ikone obvestil z nizko stopnjo prednosti"</string>
<string name="other" msgid="429768510980739978">"Drugo"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranitev ploščice"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"dodajanje ploščice na konec"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premik ploščice"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Dodajanje ploščice"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Premik na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Urejevalnik hitrih nastavitev."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Obvestilo za <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Odpri nastavitve."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e117602afa9a..90f1c5adf7be 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -884,20 +884,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Прикажи иконе обавештења ниског приоритета"</string>
<string name="other" msgid="429768510980739978">"Друго"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"уклонили плочицу"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додали плочицу на крај"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместите плочицу"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додајте плочицу"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Преместите на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додајте на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уређивач за Брза подешавања."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Обавештења за <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Отвори Подешавања."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8559b0b0de2b..8918f519b020 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Visa ikoner för aviseringar med låg prioritet"</string>
<string name="other" msgid="429768510980739978">"Annat"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ta bort ruta"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"lägg till ruta i slutet"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytta ruta"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Lägg till ruta"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flytta till <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigerare för snabbinställningar."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-avisering: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Öppna inställningarna."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 76b86eee8289..3949f2df6e40 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Onyesha aikoni za arifa zisizo muhimu"</string>
<string name="other" msgid="429768510980739978">"Nyingine"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ondoa kigae"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ongeza kigae mwishoni"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hamisha kigae"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Ongeza kigae"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Hamishia kwenye <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ongeza kwenye nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kihariri cha Mipangilio ya haraka."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Arifa kutoka <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Fungua mipangilio."</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 925c958199ed..d7a27b86a99a 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"తక్కువ ప్రాధాన్యత నోటిఫికేషన్ చిహ్నాలను చూపించు"</string>
<string name="other" msgid="429768510980739978">"ఇతరం"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"టైల్‌ను తీసివేయండి"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ముగించడానికి టైల్‌ను జోడించండి"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"టైల్‌ను తరలించండి"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"టైల్‌ను జోడించండి"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g>కు తరలించండి"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> నోటిఫికేషన్: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"సెట్టింగ్‌లను తెరవండి."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c613e9c0d7c0..cb6089fa0344 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"แสดงไอคอนการแจ้งเตือนลำดับความสำคัญต่ำ"</string>
<string name="other" msgid="429768510980739978">"อื่นๆ"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"นำชิ้นส่วนออก"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"เพิ่มชิ้นส่วนต่อท้าย"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ย้ายชิ้นส่วน"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"เพิ่มชิ้นส่วน"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"ย้ายไปที่ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ตัวแก้ไขการตั้งค่าด่วน"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> การแจ้งเตือน: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"เปิดการตั้งค่า"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9411957e56f2..7e6aa629ea63 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Ipakita ang mga icon ng notification na may mababang priority"</string>
<string name="other" msgid="429768510980739978">"Iba pa"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"alisin ang tile"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"idagdag ang tile sa dulo"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Ilipat ang tile"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Magdagdag ng tile"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Ilipat sa <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor ng Mga mabilisang setting."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Notification sa <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Buksan ang mga setting."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4d46f93e2d25..dac352f79d8b 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Düşük öncelikli bildirim simgelerini göster"</string>
<string name="other" msgid="429768510980739978">"Diğer"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Karoyu kaldırmak için"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"Sona karo eklemek için"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Karoyu taşı"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Karo ekle"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna taşı"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna ekle"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Konum: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Hızlı ayar düzenleyicisi."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildirimi: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Ayarları aç."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 399b53a91de6..eeedac603ab5 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -889,20 +889,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Показувати значки сповіщень із низьким пріоритетом"</string>
<string name="other" msgid="429768510980739978">"Інше"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"вилучити значок"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"додати значок у кінець"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перемістити значок"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Додати значок"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перемістити на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор швидких налаштувань."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Сповіщення <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Відкрити налаштування."</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 09e500d227a6..4bd192fd63f0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"کم ترجیحی اطلاع کے آئیکنز دکھائیں"</string>
<string name="other" msgid="429768510980739978">"دیگر"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ٹائل ہٹائیں"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"ختم کرنے کے لیے ٹائل شامل کریں"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ٹائل منتقل کریں"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"ٹائل شامل کریں"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"<xliff:g id="POSITION">%1$d</xliff:g> میں منتقل کریں"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"فوری ترتیبات کا ایڈیٹر۔"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> اطلاع: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"ترتیبات کھولیں۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 61b91c768582..7c3728abab78 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Muhim boʻlmagan bildirishnoma ikonkalarini koʻrsatish"</string>
<string name="other" msgid="429768510980739978">"Boshqa"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"katakchani olib tashlash"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"oxiriga katakcha kiritish"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Katakchani boshqa joyga olish"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Katakcha kiritish"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Bu joyga olish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bu joyga kiritish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Tezkor sozlamalar muharriri"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> bildirishnomasi: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Sozlamalarni ochish."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dc2a5b826439..f23f7424a073 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Hiển thị biểu tượng thông báo có mức ưu tiên thấp"</string>
<string name="other" msgid="429768510980739978">"Khác"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"xóa ô"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"thêm ô vào cuối"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Di chuyển ô"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Thêm ô"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Di chuyển tới <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Thêm vào vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Trình chỉnh sửa cài đặt nhanh."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"Thông báo của <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Mở phần cài đặt."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 71a7d8e7165d..9b81cb04db1a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"显示低优先级的通知图标"</string>
<string name="other" msgid="429768510980739978">"其他"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除图块"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"将图块添加到末尾"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动图块"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"添加图块"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快捷设置编辑器。"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"打开设置。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 1d763d010984..facb47a3bdfc 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"顯示低優先順序通知圖示"</string>
<string name="other" msgid="429768510980739978">"其他"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"將圖塊加到結尾"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移圖塊"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"加圖塊"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移去 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"加去位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯工具。"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"開啟設定。"</string>
@@ -975,7 +968,7 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"省電模式將會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
- <string name="heap_dump_tile_name" msgid="2464189856478823046">"轉儲 SysUI 堆"</string>
+ <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
<string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 303ddd925a86..4e4db70ddd67 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"顯示低優先順序通知圖示"</string>
<string name="other" msgid="429768510980739978">"其他"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除圖塊"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"將圖塊加到結尾處"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移動圖塊"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"新增圖塊"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"移至 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"新增到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯器。"</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> 通知:<xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"開啟設定。"</string>
@@ -975,7 +968,7 @@
<string name="auto_saver_enabled_text" msgid="7889491183116752719">"省電模式會在電量低於 <xliff:g id="PERCENTAGE">%d</xliff:g>%% 時自動開啟。"</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"我知道了"</string>
- <string name="heap_dump_tile_name" msgid="2464189856478823046">"傾印 SysUI 記憶體快照"</string>
+ <string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
<string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d8eb7ade9600..65e9a1c6a5e0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -879,20 +879,13 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Bonisa izithonjana zesaziso zokubaluleka okuncane"</string>
<string name="other" msgid="429768510980739978">"Okunye"</string>
- <!-- no translation found for accessibility_qs_edit_remove_tile_action (775511891457193480) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_action (5051211910345301833) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_move (2009373939914517817) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_start_add (7560798153975555772) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_move_to_position (5198161544045930556) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_tile_add_to_position (9029163095148274690) -->
- <skip />
- <!-- no translation found for accessibility_qs_edit_position (4509277359815711830) -->
- <skip />
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"susa ithayela"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"engeza ithayela ekugcineni"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hambisa ithayela"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Engeza ithayela"</string>
+ <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Hambisa ku-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engeza kusikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+ <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Isikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Isihleli sezilungiselelo ezisheshayo."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> isaziso: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Vula izilungiselelo."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 98e8cde40275..d5362baaacf0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -226,6 +226,8 @@
<dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
<dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
+ <dimen name="notification_guts_header_top_padding">11dp</dimen>
+
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
@@ -1368,9 +1370,10 @@
<dimen name="config_rounded_mask_size_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
<!-- Output switcher panel related dimensions -->
- <dimen name="media_output_dialog_padding_top">11dp</dimen>
+ <dimen name="media_output_dialog_list_margin">12dp</dimen>
<dimen name="media_output_dialog_list_max_height">364dp</dimen>
<dimen name="media_output_dialog_header_album_icon_size">52dp</dimen>
<dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
+ <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
<dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index 23195af8bdea..e99245fa438f 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -33,13 +33,9 @@ import android.view.SurfaceView;
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.systemui.dagger.qualifiers.Main;
import java.util.NoSuchElementException;
-import javax.inject.Inject;
-
/**
* Encapsulates all logic for secondary lockscreen state management.
*/
@@ -146,9 +142,9 @@ public class AdminSecondaryLockScreenController {
}
};
- private AdminSecondaryLockScreenController(Context context, KeyguardSecurityContainer parent,
+ public AdminSecondaryLockScreenController(Context context, ViewGroup parent,
KeyguardUpdateMonitor updateMonitor, KeyguardSecurityCallback callback,
- @Main Handler handler) {
+ Handler handler) {
mContext = context;
mHandler = handler;
mParent = parent;
@@ -238,26 +234,4 @@ public class AdminSecondaryLockScreenController {
getHolder().removeCallback(mSurfaceHolderCallback);
}
}
-
- @KeyguardBouncerScope
- public static class Factory {
- private final Context mContext;
- private final KeyguardSecurityContainer mParent;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final Handler mHandler;
-
- @Inject
- public Factory(Context context, KeyguardSecurityContainer parent,
- KeyguardUpdateMonitor updateMonitor, @Main Handler handler) {
- mContext = context;
- mParent = parent;
- mUpdateMonitor = updateMonitor;
- mHandler = handler;
- }
-
- public AdminSecondaryLockScreenController create(KeyguardSecurityCallback callback) {
- return new AdminSecondaryLockScreenController(mContext, mParent, mUpdateMonitor,
- callback, mHandler);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index cc6df45c598f..88f4176f5eac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -16,26 +16,46 @@
package com.android.keyguard;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.os.AsyncTask;
+import android.os.CountDownTimer;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
import android.view.View;
+import android.widget.LinearLayout;
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternChecker;
+import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
* Base class for PIN and password unlock screens.
*/
-public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
+public abstract class KeyguardAbsKeyInputView extends LinearLayout
+ implements KeyguardSecurityView, EmergencyButton.EmergencyButtonCallback {
+ protected KeyguardSecurityCallback mCallback;
+ protected LockPatternUtils mLockPatternUtils;
+ protected AsyncTask<?, ?, ?> mPendingLockCheck;
+ protected SecurityMessageDisplay mSecurityMessageDisplay;
protected View mEcaView;
protected boolean mEnableHaptics;
+ private boolean mDismissing;
+ protected boolean mResumed;
+ private CountDownTimer mCountdownTimer = null;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
protected static final int MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT = 3;
- private KeyDownListener mKeyDownListener;
public KeyguardAbsKeyInputView(Context context) {
this(context, null);
@@ -43,10 +63,38 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
public KeyguardAbsKeyInputView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
}
- void setEnableHaptics(boolean enableHaptics) {
- mEnableHaptics = enableHaptics;
+ @Override
+ public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
+ mEnableHaptics = mLockPatternUtils.isTactileFeedbackEnabled();
+ }
+
+ @Override
+ public void reset() {
+ // start fresh
+ mDismissing = false;
+ resetPasswordText(false /* animate */, false /* announce */);
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (shouldLockout(deadline)) {
+ handleAttemptLockout(deadline);
+ } else {
+ resetState();
+ }
+ }
+
+ // Allow subclasses to override this behavior
+ protected boolean shouldLockout(long deadline) {
+ return deadline != 0;
}
protected abstract int getPasswordTextViewId();
@@ -54,7 +102,24 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
@Override
protected void onFinishInflate() {
+ mLockPatternUtils = new LockPatternUtils(mContext);
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
+
+ EmergencyButton button = findViewById(R.id.emergency_call_button);
+ if (button != null) {
+ button.setCallback(this);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
+ }
+
+ @Override
+ public void onEmergencyButtonClickedWhenInCall() {
+ mCallback.reset();
}
/*
@@ -66,14 +131,195 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
return R.string.kg_wrong_password;
}
+ protected void verifyPasswordAndUnlock() {
+ if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
+
+ final LockscreenCredential password = getEnteredCredential();
+ setPasswordEntryInputEnabled(false);
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ }
+
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
+ if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ // to avoid accidental lockout, only count attempts that are long enough to be a
+ // real password. This may require some tweaking.
+ setPasswordEntryInputEnabled(true);
+ onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
+ password.zeroize();
+ return;
+ }
+
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+
+ mKeyguardUpdateMonitor.setCredentialAttempted();
+ mPendingLockCheck = LockPatternChecker.checkCredential(
+ mLockPatternUtils,
+ password,
+ userId,
+ new LockPatternChecker.OnCheckCallback() {
+
+ @Override
+ public void onEarlyMatched() {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL);
+ }
+ onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
+ true /* isValidPassword */);
+ password.zeroize();
+ }
+
+ @Override
+ public void onChecked(boolean matched, int timeoutMs) {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ setPasswordEntryInputEnabled(true);
+ mPendingLockCheck = null;
+ if (!matched) {
+ onPasswordChecked(userId, false /* matched */, timeoutMs,
+ true /* isValidPassword */);
+ }
+ password.zeroize();
+ }
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we cancelled
+ // the check. However, we still need to note down the latency.
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ password.zeroize();
+ }
+ });
+ }
+
+ private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
+ boolean isValidPassword) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
+ if (matched) {
+ mCallback.reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mDismissing = true;
+ mCallback.dismiss(true, userId);
+ }
+ } else {
+ if (isValidPassword) {
+ mCallback.reportUnlockAttempt(userId, false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ userId, timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
+ mSecurityMessageDisplay.setMessage(getWrongPasswordStringId());
+ }
+ }
+ resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
+ }
+
protected abstract void resetPasswordText(boolean animate, boolean announce);
protected abstract LockscreenCredential getEnteredCredential();
protected abstract void setPasswordEntryEnabled(boolean enabled);
protected abstract void setPasswordEntryInputEnabled(boolean enabled);
+ // Prevent user from using the PIN/Password entry until scheduled deadline.
+ protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ setPasswordEntryEnabled(false);
+ long elapsedRealtime = SystemClock.elapsedRealtime();
+ long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
+ mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
+ }
+
+ @Override
+ public void onFinish() {
+ mSecurityMessageDisplay.setMessage("");
+ resetState();
+ }
+ }.start();
+ }
+
+ protected void onUserInput() {
+ if (mCallback != null) {
+ mCallback.userActivity();
+ mCallback.onUserInput();
+ }
+ mSecurityMessageDisplay.setMessage("");
+ }
+
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- return mKeyDownListener != null && mKeyDownListener.onKeyDown(keyCode, event);
+ // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
+ // We don't want to consider it valid user input because the UI
+ // will already respond to the event.
+ if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
+ onUserInput();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean needsInput() {
+ return false;
+ }
+
+ @Override
+ public void onPause() {
+ mResumed = false;
+
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ mCountdownTimer = null;
+ }
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ mPendingLockCheck = null;
+ }
+ reset();
+ }
+
+ @Override
+ public void onResume(int reason) {
+ mResumed = true;
+ }
+
+ @Override
+ public KeyguardSecurityCallback getCallback() {
+ return mCallback;
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ if (reason != PROMPT_REASON_NONE) {
+ int promtReasonStringRes = getPromptReasonStringRes(reason);
+ if (promtReasonStringRes != 0) {
+ mSecurityMessageDisplay.setMessage(promtReasonStringRes);
+ }
+ }
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (colorState != null) {
+ mSecurityMessageDisplay.setNextMessageColor(colorState);
+ }
+ mSecurityMessageDisplay.setMessage(message);
}
protected abstract int getPromptReasonStringRes(int reason);
@@ -87,12 +333,9 @@ public abstract class KeyguardAbsKeyInputView extends KeyguardInputView {
}
}
- public void setKeyDownListener(KeyDownListener keyDownListener) {
- mKeyDownListener = keyDownListener;
- }
-
- public interface KeyDownListener {
- boolean onKeyDown(int keyCode, KeyEvent keyEvent);
+ @Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return false;
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
deleted file mode 100644
index d957628c52ab..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
-import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
-
-import android.content.res.ColorStateList;
-import android.os.AsyncTask;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternChecker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockscreenCredential;
-import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
-import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-
-public abstract class KeyguardAbsKeyInputViewController<T extends KeyguardAbsKeyInputView>
- extends KeyguardInputViewController<T> {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final LockPatternUtils mLockPatternUtils;
- private final LatencyTracker mLatencyTracker;
- private CountDownTimer mCountdownTimer;
- protected KeyguardMessageAreaController mMessageAreaController;
- private boolean mDismissing;
- protected AsyncTask<?, ?, ?> mPendingLockCheck;
- protected boolean mResumed;
-
- private final KeyDownListener mKeyDownListener = (keyCode, keyEvent) -> {
- // Fingerprint sensor sends a KeyEvent.KEYCODE_UNKNOWN.
- // We don't want to consider it valid user input because the UI
- // will already respond to the event.
- if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
- onUserInput();
- }
- return false;
- };
-
- private final EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
- @Override
- public void onEmergencyButtonClickedWhenInCall() {
- getKeyguardSecurityCallback().reset();
- }
- };
-
- protected KeyguardAbsKeyInputViewController(T view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode,
- LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker) {
- super(view, securityMode, keyguardSecurityCallback);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mLockPatternUtils = lockPatternUtils;
- mLatencyTracker = latencyTracker;
- KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
- mMessageAreaController = messageAreaControllerFactory.create(kma);
- }
-
- abstract void resetState();
-
- @Override
- public void init() {
- super.init();
- mMessageAreaController.init();
- }
-
- @Override
- protected void onViewAttached() {
- mView.setKeyDownListener(mKeyDownListener);
- mView.setEnableHaptics(mLockPatternUtils.isTactileFeedbackEnabled());
- EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
- if (button != null) {
- button.setCallback(mEmergencyButtonCallback);
- }
- }
-
- @Override
- public void reset() {
- // start fresh
- mDismissing = false;
- mView.resetPasswordText(false /* animate */, false /* announce */);
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (shouldLockout(deadline)) {
- handleAttemptLockout(deadline);
- } else {
- mView.resetState();
- }
- }
-
- @Override
- public boolean needsInput() {
- return false;
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- if (colorState != null) {
- mMessageAreaController.setNextMessageColor(colorState);
- }
- mMessageAreaController.setMessage(message);
- }
-
- // Allow subclasses to override this behavior
- protected boolean shouldLockout(long deadline) {
- return deadline != 0;
- }
-
- // Prevent user from using the PIN/Password entry until scheduled deadline.
- protected void handleAttemptLockout(long elapsedRealtimeDeadline) {
- mView.setPasswordEntryEnabled(false);
- long elapsedRealtime = SystemClock.elapsedRealtime();
- long secondsInFuture = (long) Math.ceil(
- (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
- mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
-
- @Override
- public void onTick(long millisUntilFinished) {
- int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mMessageAreaController.setMessage(mView.getResources().getQuantityString(
- R.plurals.kg_too_many_failed_attempts_countdown,
- secondsRemaining, secondsRemaining));
- }
-
- @Override
- public void onFinish() {
- mMessageAreaController.setMessage("");
- resetState();
- }
- }.start();
- }
-
- void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isValidPassword) {
- boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
- if (matched) {
- getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
- if (dismissKeyguard) {
- mDismissing = true;
- getKeyguardSecurityCallback().dismiss(true, userId);
- }
- } else {
- if (isValidPassword) {
- getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- userId, timeoutMs);
- handleAttemptLockout(deadline);
- }
- }
- if (timeoutMs == 0) {
- mMessageAreaController.setMessage(mView.getWrongPasswordStringId());
- }
- }
- mView.resetPasswordText(true /* animate */, !matched /* announce deletion if no match */);
- }
-
- protected void verifyPasswordAndUnlock() {
- if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
-
- final LockscreenCredential password = mView.getEnteredCredential();
- mView.setPasswordEntryInputEnabled(false);
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- }
-
- final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (password.size() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
- // to avoid accidental lockout, only count attempts that are long enough to be a
- // real password. This may require some tweaking.
- mView.setPasswordEntryInputEnabled(true);
- onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */);
- password.zeroize();
- return;
- }
-
- mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL);
- mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
-
- mKeyguardUpdateMonitor.setCredentialAttempted();
- mPendingLockCheck = LockPatternChecker.checkCredential(
- mLockPatternUtils,
- password,
- userId,
- new LockPatternChecker.OnCheckCallback() {
-
- @Override
- public void onEarlyMatched() {
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL);
-
- onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
- true /* isValidPassword */);
- password.zeroize();
- }
-
- @Override
- public void onChecked(boolean matched, int timeoutMs) {
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- mView.setPasswordEntryInputEnabled(true);
- mPendingLockCheck = null;
- if (!matched) {
- onPasswordChecked(userId, false /* matched */, timeoutMs,
- true /* isValidPassword */);
- }
- password.zeroize();
- }
-
- @Override
- public void onCancelled() {
- // We already got dismissed with the early matched callback, so we cancelled
- // the check. However, we still need to note down the latency.
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- password.zeroize();
- }
- });
- }
-
- @Override
- public void showPromptReason(int reason) {
- if (reason != PROMPT_REASON_NONE) {
- int promtReasonStringRes = mView.getPromptReasonStringRes(reason);
- if (promtReasonStringRes != 0) {
- mMessageAreaController.setMessage(promtReasonStringRes);
- }
- }
- }
-
- protected void onUserInput() {
- getKeyguardSecurityCallback().userActivity();
- getKeyguardSecurityCallback().onUserInput();
- mMessageAreaController.setMessage("");
- }
-
- @Override
- public void onResume(int reason) {
- mResumed = true;
- }
-
- @Override
- public void onPause() {
- mResumed = false;
-
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- mCountdownTimer = null;
- }
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- mPendingLockCheck = null;
- }
- reset();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
index 36d5543f1c01..be21d203411e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java
@@ -39,6 +39,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
+import com.android.systemui.util.InjectionInflationController;
import javax.inject.Inject;
@@ -48,6 +49,7 @@ public class KeyguardDisplayManager {
private final MediaRouter mMediaRouter;
private final DisplayManager mDisplayService;
+ private final InjectionInflationController mInjectableInflater;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
@@ -90,8 +92,10 @@ public class KeyguardDisplayManager {
@Inject
public KeyguardDisplayManager(Context context,
+ InjectionInflationController injectableInflater,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
mContext = context;
+ mInjectableInflater = injectableInflater;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mMediaRouter = mContext.getSystemService(MediaRouter.class);
mDisplayService = mContext.getSystemService(DisplayManager.class);
@@ -127,7 +131,8 @@ public class KeyguardDisplayManager {
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
final Presentation newPresentation = new KeyguardPresentation(mContext, display,
- mKeyguardStatusViewComponentFactory, LayoutInflater.from(mContext));
+ mKeyguardStatusViewComponentFactory,
+ mInjectableInflater.injectable(LayoutInflater.from(mContext)));
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
mPresentations.remove(displayId);
@@ -245,7 +250,7 @@ public class KeyguardDisplayManager {
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
- private final LayoutInflater mLayoutInflater;
+ private final LayoutInflater mInjectableLayoutInflater;
private KeyguardClockSwitchController mKeyguardClockSwitchController;
private View mClock;
private int mUsableWidth;
@@ -265,10 +270,10 @@ public class KeyguardDisplayManager {
KeyguardPresentation(Context context, Display display,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
- LayoutInflater layoutInflater) {
+ LayoutInflater injectionLayoutInflater) {
super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
- mLayoutInflater = layoutInflater;
+ mInjectableLayoutInflater = injectionLayoutInflater;
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
setCancelable(false);
}
@@ -294,7 +299,7 @@ public class KeyguardDisplayManager {
mMarginLeft = (100 - VIDEO_SAFE_REGION) * p.x / 200;
mMarginTop = (100 - VIDEO_SAFE_REGION) * p.y / 200;
- setContentView(mLayoutInflater.inflate(R.layout.keyguard_presentation, null));
+ setContentView(mInjectableLayoutInflater.inflate(R.layout.keyguard_presentation, null));
// Logic to make the lock screen fullscreen
getWindow().getDecorView().setSystemUiVisibility(
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
index 9ffa658da0e8..7aabb17de90c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostViewController.java
@@ -178,18 +178,18 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
/** Initialize the Controller. */
public void init() {
super.init();
+ mView.setViewMediatorCallback(mViewMediatorCallback);
+ // Update ViewMediator with the current input method requirements
+ mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardSecurityContainerController.init();
+ mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
+ mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
protected void onViewAttached() {
- mView.setViewMediatorCallback(mViewMediatorCallback);
- // Update ViewMediator with the current input method requirements
- mViewMediatorCallback.setNeedsInput(mKeyguardSecurityContainerController.needsInput());
mKeyguardUpdateMonitor.registerCallback(mUpdateCallback);
mView.setOnKeyListener(mOnKeyListener);
- mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(false);
}
@Override
@@ -350,7 +350,7 @@ public class KeyguardHostViewController extends ViewController<KeyguardHostView>
}
public boolean handleBackKey() {
- if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
+ if (mKeyguardSecurityContainerController.getCurrentSecuritySelection()
!= SecurityMode.None) {
mKeyguardSecurityContainerController.dismiss(
false, KeyguardUpdateMonitor.getCurrentUser());
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
deleted file mode 100644
index d42a53cc875e..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputView.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.LinearLayout;
-
-import androidx.annotation.Nullable;
-
-/**
- * A Base class for all Keyguard password/pattern/pin related inputs.
- */
-public abstract class KeyguardInputView extends LinearLayout {
-
- public KeyguardInputView(Context context) {
- super(context);
- }
-
- public KeyguardInputView(Context context,
- @Nullable AttributeSet attrs) {
- super(context, attrs);
- }
-
- public KeyguardInputView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- abstract CharSequence getTitle();
-
- boolean disallowInterceptTouch(MotionEvent event) {
- return false;
- }
-
- void startAppearAnimation() {}
-
- boolean startDisappearAnimation(Runnable finishRunnable) {
- return false;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
deleted file mode 100644
index fbda818740e8..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.telephony.TelephonyManager;
-import android.view.inputmethod.InputMethodManager;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.ViewController;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-
-import javax.inject.Inject;
-
-
-/** Controller for a {@link KeyguardSecurityView}. */
-public abstract class KeyguardInputViewController<T extends KeyguardInputView>
- extends ViewController<T> implements KeyguardSecurityView {
-
- private final SecurityMode mSecurityMode;
- private final KeyguardSecurityCallback mKeyguardSecurityCallback;
- private boolean mPaused;
-
-
- // The following is used to ignore callbacks from SecurityViews that are no longer current
- // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
- // state for the current security method.
- private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
- @Override
- public void userActivity() { }
- @Override
- public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
- @Override
- public boolean isVerifyUnlockOnly() {
- return false;
- }
- @Override
- public void dismiss(boolean securityVerified, int targetUserId) { }
- @Override
- public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) { }
- @Override
- public void onUserInput() { }
- @Override
- public void reset() {}
- };
-
- protected KeyguardInputViewController(T view, SecurityMode securityMode,
- KeyguardSecurityCallback keyguardSecurityCallback) {
- super(view);
- mSecurityMode = securityMode;
- mKeyguardSecurityCallback = keyguardSecurityCallback;
- }
-
- @Override
- protected void onViewAttached() {
- }
-
- @Override
- protected void onViewDetached() {
- }
-
- SecurityMode getSecurityMode() {
- return mSecurityMode;
- }
-
- protected KeyguardSecurityCallback getKeyguardSecurityCallback() {
- if (mPaused) {
- return mNullCallback;
- }
-
- return mKeyguardSecurityCallback;
- }
-
- @Override
- public void reset() {
- }
-
- @Override
- public void onPause() {
- mPaused = true;
- }
-
- @Override
- public void onResume(int reason) {
- mPaused = false;
- }
-
- @Override
- public void showPromptReason(int reason) {
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- }
-
- public void startAppearAnimation() {
- mView.startAppearAnimation();
- }
-
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return mView.startDisappearAnimation(finishRunnable);
- }
-
- @Override
- public CharSequence getTitle() {
- return mView.getTitle();
- }
-
- /** Finds the index of this view in the suppplied parent view. */
- public int getIndexIn(KeyguardSecurityViewFlipper view) {
- return view.indexOfChild(mView);
- }
-
- /** Factory for a {@link KeyguardInputViewController}. */
- public static class Factory {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final LockPatternUtils mLockPatternUtils;
- private final LatencyTracker mLatencyTracker;
- private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
- private final InputMethodManager mInputMethodManager;
- private final DelayableExecutor mMainExecutor;
- private final Resources mResources;
- private LiftToActivateListener mLiftToActivateListener;
- private TelephonyManager mTelephonyManager;
-
- @Inject
- public Factory(KeyguardUpdateMonitor keyguardUpdateMonitor,
- LockPatternUtils lockPatternUtils,
- LatencyTracker latencyTracker,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- InputMethodManager inputMethodManager, @Main DelayableExecutor mainExecutor,
- @Main Resources resources, LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mLockPatternUtils = lockPatternUtils;
- mLatencyTracker = latencyTracker;
- mMessageAreaControllerFactory = messageAreaControllerFactory;
- mInputMethodManager = inputMethodManager;
- mMainExecutor = mainExecutor;
- mResources = resources;
- mLiftToActivateListener = liftToActivateListener;
- mTelephonyManager = telephonyManager;
- }
-
- /** Create a new {@link KeyguardInputViewController}. */
- public KeyguardInputViewController create(KeyguardInputView keyguardInputView,
- SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback) {
- if (keyguardInputView instanceof KeyguardPatternView) {
- return new KeyguardPatternViewController((KeyguardPatternView) keyguardInputView,
- mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mLatencyTracker, mMessageAreaControllerFactory);
- } else if (keyguardInputView instanceof KeyguardPasswordView) {
- return new KeyguardPasswordViewController((KeyguardPasswordView) keyguardInputView,
- mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mInputMethodManager, mMainExecutor, mResources);
- } else if (keyguardInputView instanceof KeyguardPINView) {
- return new KeyguardPinViewController((KeyguardPINView) keyguardInputView,
- mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener);
- } else if (keyguardInputView instanceof KeyguardSimPinView) {
- return new KeyguardSimPinViewController((KeyguardSimPinView) keyguardInputView,
- mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager);
- } else if (keyguardInputView instanceof KeyguardSimPukView) {
- return new KeyguardSimPukViewController((KeyguardSimPukView) keyguardInputView,
- mKeyguardUpdateMonitor, securityMode, mLockPatternUtils,
- keyguardSecurityCallback, mMessageAreaControllerFactory, mLatencyTracker,
- mLiftToActivateListener, mTelephonyManager);
- }
-
- throw new RuntimeException("Unable to find controller for " + keyguardInputView);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 1a0a4370fca4..a8b1451d92c7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -16,6 +16,8 @@
package com.android.keyguard;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
+
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -29,14 +31,20 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import java.lang.ref.WeakReference;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/***
* Manages a number of views inside of the given layout. See below for a list of widgets.
*/
-public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
+public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay,
+ ConfigurationController.ConfigurationListener {
/** Handler token posted with accessibility announcement runnables. */
private static final Object ANNOUNCE_TOKEN = new Object();
@@ -48,26 +56,71 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
private static final int DEFAULT_COLOR = -1;
private final Handler mHandler;
+ private final ConfigurationController mConfigurationController;
private ColorStateList mDefaultColorState;
private CharSequence mMessage;
private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
private boolean mBouncerVisible;
- public KeyguardMessageArea(Context context, AttributeSet attrs) {
+ private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
+ public void onFinishedGoingToSleep(int why) {
+ setSelected(false);
+ }
+
+ public void onStartedWakingUp() {
+ setSelected(true);
+ }
+
+ @Override
+ public void onKeyguardBouncerChanged(boolean bouncer) {
+ mBouncerVisible = bouncer;
+ update();
+ }
+ };
+
+ public KeyguardMessageArea(Context context) {
+ super(context, null);
+ throw new IllegalStateException("This constructor should never be invoked");
+ }
+
+ @Inject
+ public KeyguardMessageArea(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
+ ConfigurationController configurationController) {
+ this(context, attrs, Dependency.get(KeyguardUpdateMonitor.class), configurationController);
+ }
+
+ public KeyguardMessageArea(Context context, AttributeSet attrs, KeyguardUpdateMonitor monitor,
+ ConfigurationController configurationController) {
super(context, attrs);
setLayerType(LAYER_TYPE_HARDWARE, null); // work around nested unclipped SaveLayer bug
+ monitor.registerCallback(mInfoCallback);
mHandler = new Handler(Looper.myLooper());
+ mConfigurationController = configurationController;
onThemeChanged();
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mConfigurationController.addCallback(this);
+ onThemeChanged();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mConfigurationController.removeCallback(this);
+ }
+
+ @Override
public void setNextMessageColor(ColorStateList colorState) {
mNextMessageColorState = colorState;
}
- void onThemeChanged() {
+ @Override
+ public void onThemeChanged() {
TypedArray array = mContext.obtainStyledAttributes(new int[] {
R.attr.wallpaperTextColor
});
@@ -77,7 +130,8 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
- void onDensityOrFontScaleChanged() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
TypedArray array = mContext.obtainStyledAttributes(R.style.Keyguard_TextView, new int[] {
android.R.attr.textSize
});
@@ -123,6 +177,12 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
return messageArea;
}
+ @Override
+ protected void onFinishInflate() {
+ boolean shouldMarquee = Dependency.get(KeyguardUpdateMonitor.class).isDeviceInteractive();
+ setSelected(shouldMarquee); // This is required to ensure marquee works
+ }
+
private void securityMessageChanged(CharSequence message) {
mMessage = message;
update();
@@ -136,7 +196,7 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
update();
}
- void update() {
+ private void update() {
CharSequence status = mMessage;
setVisibility(TextUtils.isEmpty(status) || !mBouncerVisible ? INVISIBLE : VISIBLE);
setText(status);
@@ -148,9 +208,6 @@ public class KeyguardMessageArea extends TextView implements SecurityMessageDisp
setTextColor(colorState);
}
- public void setBouncerVisible(boolean bouncerVisible) {
- mBouncerVisible = bouncerVisible;
- }
/**
* Runnable used to delay accessibility announcements.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 1618e8e58055..f056bdbb9706 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -16,10 +16,7 @@
package com.android.keyguard;
-import android.content.res.ColorStateList;
-
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
@@ -29,35 +26,6 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
-
- private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
- public void onFinishedGoingToSleep(int why) {
- mView.setSelected(false);
- }
-
- public void onStartedWakingUp() {
- mView.setSelected(true);
- }
-
- @Override
- public void onKeyguardBouncerChanged(boolean bouncer) {
- mView.setBouncerVisible(bouncer);
- mView.update();
- }
- };
-
- private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
- @Override
- public void onThemeChanged() {
- mView.onThemeChanged();
- }
-
- @Override
- public void onDensityOrFontScaleChanged() {
- mView.onDensityOrFontScaleChanged();
- }
- };
-
private KeyguardMessageAreaController(KeyguardMessageArea view,
KeyguardUpdateMonitor keyguardUpdateMonitor,
ConfigurationController configurationController) {
@@ -69,31 +37,17 @@ public class KeyguardMessageAreaController extends ViewController<KeyguardMessag
@Override
protected void onViewAttached() {
- mConfigurationController.addCallback(mConfigurationListener);
- mKeyguardUpdateMonitor.registerCallback(mInfoCallback);
- mView.setSelected(mKeyguardUpdateMonitor.isDeviceInteractive());
- mView.onThemeChanged();
+ //mConfigurationController.addCallback();
+ //mKeyguardUpdateMonitor.registerCallback();
}
@Override
protected void onViewDetached() {
- mConfigurationController.removeCallback(mConfigurationListener);
- mKeyguardUpdateMonitor.removeCallback(mInfoCallback);
- }
-
- public void setMessage(CharSequence s) {
- mView.setMessage(s);
- }
-
- public void setMessage(int resId) {
- mView.setMessage(resId);
- }
-
- public void setNextMessageColor(ColorStateList colorState) {
- mView.setNextMessageColor(colorState);
+ //mConfigurationController.removeCallback();
+ //mKeyguardUpdateMonitor.removeCallback();
}
- /** Factory for creating {@link com.android.keyguard.KeyguardMessageAreaController}. */
+ /** Factory for createing {@link com.android.keyguard.KeyguardMessageAreaController}. */
public static class Factory {
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final ConfigurationController mConfigurationController;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 580d7043a220..12ea1d586e10 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -24,6 +24,7 @@ import android.view.animation.AnimationUtils;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
@@ -39,8 +40,10 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
private ViewGroup mRow1;
private ViewGroup mRow2;
private ViewGroup mRow3;
+ private View mDivider;
private int mDisappearYTranslation;
private View[][] mViews;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
public KeyguardPINView(Context context) {
this(context, null);
@@ -60,10 +63,15 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
mContext, android.R.interpolator.fast_out_linear_in));
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
+ mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
}
@Override
protected void resetState() {
+ super.resetState();
+ if (mSecurityMessageDisplay != null) {
+ mSecurityMessageDisplay.setMessage("");
+ }
}
@Override
@@ -80,6 +88,7 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
mRow1 = findViewById(R.id.row1);
mRow2 = findViewById(R.id.row2);
mRow3 = findViewById(R.id.row3);
+ mDivider = findViewById(R.id.divider);
mViews = new View[][]{
new View[]{
mRow0, null, null
@@ -103,6 +112,18 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
new View[]{
null, mEcaView, null
}};
+
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ mCallback.onCancelClicked();
+ });
+ }
+ }
+
+ @Override
+ public void showUsabilityHint() {
}
@Override
@@ -126,21 +147,24 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
});
}
- public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
- final Runnable finishRunnable) {
-
+ @Override
+ public boolean startDisappearAnimation(final Runnable finishRunnable) {
enableClipping(false);
setTranslationY(0);
AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
- DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
+ DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+ .needsSlowUnlockTransition()
? mDisappearAnimationUtilsLocked
: mDisappearAnimationUtils;
disappearAnimationUtils.startAnimation2d(mViews,
- () -> {
- enableClipping(true);
- if (finishRunnable != null) {
- finishRunnable.run();
+ new Runnable() {
+ @Override
+ public void run() {
+ enableClipping(true);
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
}
});
return true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index aaa5efec807e..97317cf5580f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -16,37 +16,50 @@
package com.android.keyguard;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
-
import android.content.Context;
import android.graphics.Rect;
+import android.os.UserHandle;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.text.method.TextKeyListener;
import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
import com.android.systemui.R;
+
+import java.util.List;
/**
* Displays an alphanumeric (latin-1) key entry for the user to enter
* an unlock password
*/
-public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
+public class KeyguardPasswordView extends KeyguardAbsKeyInputView
+ implements KeyguardSecurityView, OnEditorActionListener, TextWatcher {
+ private final boolean mShowImeAtScreenOn;
private final int mDisappearYTranslation;
// A delay constant to be used in a workaround for the situation where InputMethodManagerService
// is not switched to the new user yet.
// TODO: Remove this by ensuring such a race condition never happens.
+ private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms
+ InputMethodManager mImm;
private TextView mPasswordEntry;
private TextViewInputDisabler mPasswordEntryDisabler;
+ private View mSwitchImeButton;
private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutLinearInInterpolator;
@@ -57,6 +70,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
public KeyguardPasswordView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mShowImeAtScreenOn = context.getResources().
+ getBoolean(R.bool.kg_show_ime_at_screen_on);
mDisappearYTranslation = getResources().getDimensionPixelSize(
R.dimen.disappear_y_translation);
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
@@ -67,6 +82,20 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
@Override
protected void resetState() {
+ mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
+ if (mSecurityMessageDisplay != null) {
+ mSecurityMessageDisplay.setMessage("");
+ }
+ final boolean wasDisabled = mPasswordEntry.isEnabled();
+ setPasswordEntryEnabled(true);
+ setPasswordEntryInputEnabled(true);
+ // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage.
+ if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
+ return;
+ }
+ if (wasDisabled) {
+ mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ }
}
@Override
@@ -75,6 +104,29 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
}
@Override
+ public boolean needsInput() {
+ return true;
+ }
+
+ @Override
+ public void onResume(final int reason) {
+ super.onResume(reason);
+
+ // Wait a bit to focus the field so the focusable flag on the window is already set then.
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (isShown() && mPasswordEntry.isEnabled()) {
+ mPasswordEntry.requestFocus();
+ if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
+ mImm.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
+ }
+ }
+ }
+ });
+ }
+
+ @Override
protected int getPromptReasonStringRes(int reason) {
switch (reason) {
case PROMPT_REASON_RESTART:
@@ -94,13 +146,97 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
}
}
+ @Override
+ public void onPause() {
+ super.onPause();
+ mImm.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
+
+ @Override
+ public void onStartingToHide() {
+ mImm.hideSoftInputFromWindow(getWindowToken(), 0);
+ }
+
+ private void updateSwitchImeButton() {
+ // If there's more than one IME, enable the IME switcher button
+ final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
+ final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(mImm, false);
+ if (wasVisible != shouldBeVisible) {
+ mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
+ }
+
+ // TODO: Check if we still need this hack.
+ // If no icon is visible, reset the start margin on the password field so the text is
+ // still centered.
+ if (mSwitchImeButton.getVisibility() != View.VISIBLE) {
+ android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
+ if (params instanceof MarginLayoutParams) {
+ final MarginLayoutParams mlp = (MarginLayoutParams) params;
+ mlp.setMarginStart(0);
+ mPasswordEntry.setLayoutParams(params);
+ }
+ }
+ }
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mImm = (InputMethodManager) getContext().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+
mPasswordEntry = findViewById(getPasswordTextViewId());
+ mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
mPasswordEntryDisabler = new TextViewInputDisabler(mPasswordEntry);
+ mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ mPasswordEntry.setOnEditorActionListener(this);
+ mPasswordEntry.addTextChangedListener(this);
+
+ // Poke the wakelock any time the text is selected or modified
+ mPasswordEntry.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCallback.userActivity();
+ }
+ });
+
+ // Set selected property on so the view can send accessibility events.
+ mPasswordEntry.setSelected(true);
+
+ mSwitchImeButton = findViewById(R.id.switch_ime_button);
+ mSwitchImeButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mCallback.userActivity(); // Leave the screen on a bit longer
+ // Do not show auxiliary subtypes in password lock screen.
+ mImm.showInputMethodPickerFromSystem(false /* showAuxiliarySubtypes */,
+ getContext().getDisplayId());
+ }
+ });
+
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ mCallback.onCancelClicked();
+ });
+ }
+
+ // If there's more than one IME, enable the IME switcher button
+ updateSwitchImeButton();
+
+ // When we the current user is switching, InputMethodManagerService sometimes has not
+ // switched internal state yet here. As a quick workaround, we check the keyboard state
+ // again.
+ // TODO: Remove this workaround by ensuring such a race condition never happens.
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ updateSwitchImeButton();
+ }
+ }, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
}
@Override
@@ -129,6 +265,59 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
mPasswordEntryDisabler.setInputEnabled(enabled);
}
+ /**
+ * Method adapted from com.android.inputmethod.latin.Utils
+ *
+ * @param imm The input method manager
+ * @param shouldIncludeAuxiliarySubtypes
+ * @return true if we have multiple IMEs to choose from
+ */
+ private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+ final boolean shouldIncludeAuxiliarySubtypes) {
+ final List<InputMethodInfo> enabledImis =
+ imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
+
+ // Number of the filtered IMEs
+ int filteredImisCount = 0;
+
+ for (InputMethodInfo imi : enabledImis) {
+ // We can return true immediately after we find two or more filtered IMEs.
+ if (filteredImisCount > 1) return true;
+ final List<InputMethodSubtype> subtypes =
+ imm.getEnabledInputMethodSubtypeList(imi, true);
+ // IMEs that have no subtypes should be counted.
+ if (subtypes.isEmpty()) {
+ ++filteredImisCount;
+ continue;
+ }
+
+ int auxCount = 0;
+ for (InputMethodSubtype subtype : subtypes) {
+ if (subtype.isAuxiliary()) {
+ ++auxCount;
+ }
+ }
+ final int nonAuxCount = subtypes.size() - auxCount;
+
+ // IMEs that have one or more non-auxiliary subtypes should be counted.
+ // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+ // subtypes should be counted as well.
+ if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+ ++filteredImisCount;
+ continue;
+ }
+ }
+
+ return filteredImisCount > 1
+ // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
+ // input method subtype (The current IME should be LatinIME.)
+ || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
+ }
+
+ @Override
+ public void showUsabilityHint() {
+ }
+
@Override
public int getWrongPasswordStringId() {
return R.string.kg_wrong_password;
@@ -157,8 +346,45 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
}
@Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ if (mCallback != null) {
+ mCallback.userActivity();
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // Poor man's user edit detection, assuming empty text is programmatic and everything else
+ // is from the user.
+ if (!TextUtils.isEmpty(s)) {
+ onUserInput();
+ }
+ }
+
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter key
+ final boolean isSoftImeEvent = event == null
+ && (actionId == EditorInfo.IME_NULL
+ || actionId == EditorInfo.IME_ACTION_DONE
+ || actionId == EditorInfo.IME_ACTION_NEXT);
+ final boolean isKeyboardEnterKey = event != null
+ && KeyEvent.isConfirmKey(event.getKeyCode())
+ && event.getAction() == KeyEvent.ACTION_DOWN;
+ if (isSoftImeEvent || isKeyboardEnterKey) {
+ verifyPasswordAndUnlock();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public CharSequence getTitle() {
- return getResources().getString(
+ return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
deleted file mode 100644
index d34ea8c5e018..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.content.res.Resources;
-import android.os.UserHandle;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.method.TextKeyListener;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.InputMethodSubtype;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.util.concurrency.DelayableExecutor;
-
-import java.util.List;
-
-public class KeyguardPasswordViewController
- extends KeyguardAbsKeyInputViewController<KeyguardPasswordView> {
-
- private static final int DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON = 500; // 500ms
-
- private final KeyguardSecurityCallback mKeyguardSecurityCallback;
- private final InputMethodManager mInputMethodManager;
- private final DelayableExecutor mMainExecutor;
- private final boolean mShowImeAtScreenOn;
- private TextView mPasswordEntry;
- private View mSwitchImeButton;
-
- private final OnEditorActionListener mOnEditorActionListener = (v, actionId, event) -> {
- // Check if this was the result of hitting the enter key
- final boolean isSoftImeEvent = event == null
- && (actionId == EditorInfo.IME_NULL
- || actionId == EditorInfo.IME_ACTION_DONE
- || actionId == EditorInfo.IME_ACTION_NEXT);
- final boolean isKeyboardEnterKey = event != null
- && KeyEvent.isConfirmKey(event.getKeyCode())
- && event.getAction() == KeyEvent.ACTION_DOWN;
- if (isSoftImeEvent || isKeyboardEnterKey) {
- verifyPasswordAndUnlock();
- return true;
- }
- return false;
- };
-
- private final TextWatcher mTextWatcher = new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- mKeyguardSecurityCallback.userActivity();
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- if (!TextUtils.isEmpty(s)) {
- onUserInput();
- }
- }
- };
-
- protected KeyguardPasswordViewController(KeyguardPasswordView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode,
- LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- InputMethodManager inputMethodManager,
- @Main DelayableExecutor mainExecutor,
- @Main Resources resources) {
- super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker);
- mKeyguardSecurityCallback = keyguardSecurityCallback;
- mInputMethodManager = inputMethodManager;
- mMainExecutor = mainExecutor;
- mShowImeAtScreenOn = resources.getBoolean(R.bool.kg_show_ime_at_screen_on);
- mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
- mSwitchImeButton = mView.findViewById(R.id.switch_ime_button);
- }
-
- @Override
- protected void onViewAttached() {
- super.onViewAttached();
- mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
- mPasswordEntry.setKeyListener(TextKeyListener.getInstance());
- mPasswordEntry.setInputType(InputType.TYPE_CLASS_TEXT
- | InputType.TYPE_TEXT_VARIATION_PASSWORD);
-
- // Set selected property on so the view can send accessibility events.
- mPasswordEntry.setSelected(true);
- mPasswordEntry.setOnEditorActionListener(mOnEditorActionListener);
- mPasswordEntry.addTextChangedListener(mTextWatcher);
- // Poke the wakelock any time the text is selected or modified
- mPasswordEntry.setOnClickListener(v -> mKeyguardSecurityCallback.userActivity());
-
- mSwitchImeButton.setOnClickListener(v -> {
- mKeyguardSecurityCallback.userActivity(); // Leave the screen on a bit longer
- // Do not show auxiliary subtypes in password lock screen.
- mInputMethodManager.showInputMethodPickerFromSystem(false,
- mView.getContext().getDisplayId());
- });
-
- View cancelBtn = mView.findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- mKeyguardSecurityCallback.reset();
- mKeyguardSecurityCallback.onCancelClicked();
- });
- }
-
- // If there's more than one IME, enable the IME switcher button
- updateSwitchImeButton();
-
- // When we the current user is switching, InputMethodManagerService sometimes has not
- // switched internal state yet here. As a quick workaround, we check the keyboard state
- // again.
- // TODO: Remove this workaround by ensuring such a race condition never happens.
- mMainExecutor.executeDelayed(
- this::updateSwitchImeButton, DELAY_MILLIS_TO_REEVALUATE_IME_SWITCH_ICON);
- }
-
- @Override
- protected void onViewDetached() {
- super.onViewDetached();
- mPasswordEntry.setOnEditorActionListener(null);
- }
-
- @Override
- public boolean needsInput() {
- return true;
- }
-
- @Override
- void resetState() {
- mPasswordEntry.setTextOperationUser(UserHandle.of(KeyguardUpdateMonitor.getCurrentUser()));
- mMessageAreaController.setMessage("");
- final boolean wasDisabled = mPasswordEntry.isEnabled();
- mView.setPasswordEntryEnabled(true);
- mView.setPasswordEntryInputEnabled(true);
- // Don't call showSoftInput when PasswordEntry is invisible or in pausing stage.
- if (!mResumed || !mPasswordEntry.isVisibleToUser()) {
- return;
- }
- if (wasDisabled) {
- mInputMethodManager.showSoftInput(mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
- }
- }
-
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- // Wait a bit to focus the field so the focusable flag on the window is already set then.
- mMainExecutor.execute(() -> {
- if (mView.isShown() && mPasswordEntry.isEnabled()) {
- mPasswordEntry.requestFocus();
- if (reason != KeyguardSecurityView.SCREEN_ON || mShowImeAtScreenOn) {
- mInputMethodManager.showSoftInput(
- mPasswordEntry, InputMethodManager.SHOW_IMPLICIT);
- }
- }
- });
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
- }
-
- @Override
- public void onStartingToHide() {
- mInputMethodManager.hideSoftInputFromWindow(mView.getWindowToken(), 0);
- }
-
- private void updateSwitchImeButton() {
- // If there's more than one IME, enable the IME switcher button
- final boolean wasVisible = mSwitchImeButton.getVisibility() == View.VISIBLE;
- final boolean shouldBeVisible = hasMultipleEnabledIMEsOrSubtypes(
- mInputMethodManager, false);
- if (wasVisible != shouldBeVisible) {
- mSwitchImeButton.setVisibility(shouldBeVisible ? View.VISIBLE : View.GONE);
- }
-
- // TODO: Check if we still need this hack.
- // If no icon is visible, reset the start margin on the password field so the text is
- // still centered.
- if (mSwitchImeButton.getVisibility() != View.VISIBLE) {
- android.view.ViewGroup.LayoutParams params = mPasswordEntry.getLayoutParams();
- if (params instanceof MarginLayoutParams) {
- final MarginLayoutParams mlp = (MarginLayoutParams) params;
- mlp.setMarginStart(0);
- mPasswordEntry.setLayoutParams(params);
- }
- }
- }
-
- /**
- * Method adapted from com.android.inputmethod.latin.Utils
- *
- * @param imm The input method manager
- * @param shouldIncludeAuxiliarySubtypes
- * @return true if we have multiple IMEs to choose from
- */
- private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
- final boolean shouldIncludeAuxiliarySubtypes) {
- final List<InputMethodInfo> enabledImis =
- imm.getEnabledInputMethodListAsUser(KeyguardUpdateMonitor.getCurrentUser());
-
- // Number of the filtered IMEs
- int filteredImisCount = 0;
-
- for (InputMethodInfo imi : enabledImis) {
- // We can return true immediately after we find two or more filtered IMEs.
- if (filteredImisCount > 1) return true;
- final List<InputMethodSubtype> subtypes =
- imm.getEnabledInputMethodSubtypeList(imi, true);
- // IMEs that have no subtypes should be counted.
- if (subtypes.isEmpty()) {
- ++filteredImisCount;
- continue;
- }
-
- int auxCount = 0;
- for (InputMethodSubtype subtype : subtypes) {
- if (subtype.isAuxiliary()) {
- ++auxCount;
- }
- }
- final int nonAuxCount = subtypes.size() - auxCount;
-
- // IMEs that have one or more non-auxiliary subtypes should be counted.
- // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
- // subtypes should be counted as well.
- if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
- ++filteredImisCount;
- continue;
- }
- }
-
- return filteredImisCount > 1
- // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's
- //enabled input method subtype (The current IME should be LatinIME.)
- || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index bdcf467c2456..c4a9fcb45284 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,39 +15,62 @@
*/
package com.android.keyguard;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+
import android.content.Context;
+import android.content.res.ColorStateList;
import android.graphics.Rect;
+import android.os.AsyncTask;
+import android.os.CountDownTimer;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.LatencyTracker;
+import com.android.internal.widget.LockPatternChecker;
+import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
+import com.android.internal.widget.LockscreenCredential;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
-public class KeyguardPatternView extends KeyguardInputView
- implements AppearAnimationCreator<LockPatternView.CellState> {
+import java.util.List;
+
+public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
+ AppearAnimationCreator<LockPatternView.CellState>,
+ EmergencyButton.EmergencyButtonCallback {
private static final String TAG = "SecurityPatternView";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ // how long before we clear the wrong pattern
+ private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
// how long we stay awake after each key beyond MIN_PATTERN_BEFORE_POKE_WAKELOCK
private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
+ // how many cells the user has to cross before we poke the wakelock
+ private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
+
// How much we scale up the duration of the disappear animation when the current user is locked
public static final float DISAPPEAR_MULTIPLIER_LOCKED = 1.5f;
// Extra padding, in pixels, that should eat touch events.
private static final int PATTERNS_TOUCH_AREA_EXTENSION = 40;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final AppearAnimationUtils mAppearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtils;
private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
@@ -55,7 +78,11 @@ public class KeyguardPatternView extends KeyguardInputView
private final Rect mTempRect = new Rect();
private final Rect mLockPatternScreenBounds = new Rect();
+ private CountDownTimer mCountdownTimer = null;
+ private LockPatternUtils mLockPatternUtils;
+ private AsyncTask<?, ?, ?> mPendingLockCheck;
private LockPatternView mLockPatternView;
+ private KeyguardSecurityCallback mCallback;
/**
* Keeps track of the last time we poked the wake lock during dispatching of the touch event.
@@ -65,9 +92,26 @@ public class KeyguardPatternView extends KeyguardInputView
*/
private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
+ /**
+ * Useful for clearing out the wrong pattern after a delay
+ */
+ private Runnable mCancelPatternRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mLockPatternView.clearPattern();
+ }
+ };
+ @VisibleForTesting
KeyguardMessageArea mSecurityMessageDisplay;
private View mEcaView;
private ViewGroup mContainer;
+ private int mDisappearYTranslation;
+
+ enum FooterMode {
+ Normal,
+ ForgotLockPattern,
+ VerifyUnlocked
+ }
public KeyguardPatternView(Context context) {
this(context, null);
@@ -75,6 +119,7 @@ public class KeyguardPatternView extends KeyguardInputView
public KeyguardPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
mAppearAnimationUtils = new AppearAnimationUtils(context,
AppearAnimationUtils.DEFAULT_APPEAR_DURATION, 1.5f /* translationScale */,
2.0f /* delayScale */, AnimationUtils.loadInterpolator(
@@ -87,16 +132,50 @@ public class KeyguardPatternView extends KeyguardInputView
(long) (125 * DISAPPEAR_MULTIPLIER_LOCKED), 1.2f /* translationScale */,
0.6f /* delayScale */, AnimationUtils.loadInterpolator(
mContext, android.R.interpolator.fast_out_linear_in));
+ mDisappearYTranslation = getResources().getDimensionPixelSize(
+ R.dimen.disappear_y_translation);
+ }
+
+ @Override
+ public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mLockPatternUtils = mLockPatternUtils == null
+ ? new LockPatternUtils(mContext) : mLockPatternUtils;
mLockPatternView = findViewById(R.id.lockPatternView);
+ mLockPatternView.setSaveEnabled(false);
+ mLockPatternView.setOnPatternListener(new UnlockPatternListener());
+ mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
+
+ // vibrate mode will be the same for the life of this screen
+ mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
mEcaView = findViewById(R.id.keyguard_selector_fade_container);
mContainer = findViewById(R.id.container);
+
+ EmergencyButton button = findViewById(R.id.emergency_call_button);
+ if (button != null) {
+ button.setCallback(this);
+ }
+
+ View cancelBtn = findViewById(R.id.cancel_button);
+ if (cancelBtn != null) {
+ cancelBtn.setOnClickListener(view -> {
+ mCallback.reset();
+ mCallback.onCancelClicked();
+ });
+ }
}
@Override
@@ -106,6 +185,11 @@ public class KeyguardPatternView extends KeyguardInputView
}
@Override
+ public void onEmergencyButtonClickedWhenInCall() {
+ mCallback.reset();
+ }
+
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
boolean result = super.onTouchEvent(ev);
// as long as the user is entering a pattern (i.e sending a touch event that was handled
@@ -133,11 +217,248 @@ public class KeyguardPatternView extends KeyguardInputView
}
@Override
- boolean disallowInterceptTouch(MotionEvent event) {
+ public void reset() {
+ // reset lock pattern
+ mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
+ KeyguardUpdateMonitor.getCurrentUser()));
+ mLockPatternView.enableInput();
+ mLockPatternView.setEnabled(true);
+ mLockPatternView.clearPattern();
+
+ if (mSecurityMessageDisplay == null) {
+ return;
+ }
+
+ // if the user is currently locked out, enforce it.
+ long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser());
+ if (deadline != 0) {
+ handleAttemptLockout(deadline);
+ } else {
+ displayDefaultSecurityMessage();
+ }
+ }
+
+ private void displayDefaultSecurityMessage() {
+ if (mSecurityMessageDisplay != null) {
+ mSecurityMessageDisplay.setMessage("");
+ }
+ }
+
+ @Override
+ public void showUsabilityHint() {
+ }
+
+ @Override
+ public boolean disallowInterceptTouch(MotionEvent event) {
return !mLockPatternView.isEmpty()
|| mLockPatternScreenBounds.contains((int) event.getRawX(), (int) event.getRawY());
}
+ /** TODO: hook this up */
+ public void cleanUp() {
+ if (DEBUG) Log.v(TAG, "Cleanup() called on " + this);
+ mLockPatternUtils = null;
+ mLockPatternView.setOnPatternListener(null);
+ }
+
+ private class UnlockPatternListener implements LockPatternView.OnPatternListener {
+
+ @Override
+ public void onPatternStart() {
+ mLockPatternView.removeCallbacks(mCancelPatternRunnable);
+ mSecurityMessageDisplay.setMessage("");
+ }
+
+ @Override
+ public void onPatternCleared() {
+ }
+
+ @Override
+ public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
+ mCallback.userActivity();
+ mCallback.onUserInput();
+ }
+
+ @Override
+ public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
+ mKeyguardUpdateMonitor.setCredentialAttempted();
+ mLockPatternView.disableInput();
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ }
+
+ final int userId = KeyguardUpdateMonitor.getCurrentUser();
+ if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+ mLockPatternView.enableInput();
+ onPatternChecked(userId, false, 0, false /* not valid - too short */);
+ return;
+ }
+
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ mPendingLockCheck = LockPatternChecker.checkCredential(
+ mLockPatternUtils,
+ LockscreenCredential.createPattern(pattern),
+ userId,
+ new LockPatternChecker.OnCheckCallback() {
+
+ @Override
+ public void onEarlyMatched() {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL);
+ }
+ onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
+ true /* isValidPattern */);
+ }
+
+ @Override
+ public void onChecked(boolean matched, int timeoutMs) {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ mLockPatternView.enableInput();
+ mPendingLockCheck = null;
+ if (!matched) {
+ onPatternChecked(userId, false /* matched */, timeoutMs,
+ true /* isValidPattern */);
+ }
+ }
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we
+ // cancelled the check. However, we still need to note down the latency.
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ }
+ });
+ if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
+ mCallback.userActivity();
+ mCallback.onUserInput();
+ }
+ }
+
+ private void onPatternChecked(int userId, boolean matched, int timeoutMs,
+ boolean isValidPattern) {
+ boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
+ if (matched) {
+ mCallback.reportUnlockAttempt(userId, true, 0);
+ if (dismissKeyguard) {
+ mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
+ mCallback.dismiss(true, userId);
+ }
+ } else {
+ mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
+ if (isValidPattern) {
+ mCallback.reportUnlockAttempt(userId, false, timeoutMs);
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ userId, timeoutMs);
+ handleAttemptLockout(deadline);
+ }
+ }
+ if (timeoutMs == 0) {
+ mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern);
+ mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
+ }
+ }
+ }
+ }
+
+ private void handleAttemptLockout(long elapsedRealtimeDeadline) {
+ mLockPatternView.clearPattern();
+ mLockPatternView.setEnabled(false);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long secondsInFuture = (long) Math.ceil(
+ (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
+ mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
+ mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
+ }
+
+ @Override
+ public void onFinish() {
+ mLockPatternView.setEnabled(true);
+ displayDefaultSecurityMessage();
+ }
+
+ }.start();
+ }
+
+ @Override
+ public boolean needsInput() {
+ return false;
+ }
+
+ @Override
+ public void onPause() {
+ if (mCountdownTimer != null) {
+ mCountdownTimer.cancel();
+ mCountdownTimer = null;
+ }
+ if (mPendingLockCheck != null) {
+ mPendingLockCheck.cancel(false);
+ mPendingLockCheck = null;
+ }
+ displayDefaultSecurityMessage();
+ }
+
+ @Override
+ public void onResume(int reason) {
+ }
+
+ @Override
+ public KeyguardSecurityCallback getCallback() {
+ return mCallback;
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ switch (reason) {
+ case PROMPT_REASON_RESTART:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern);
+ break;
+ case PROMPT_REASON_TIMEOUT:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ case PROMPT_REASON_DEVICE_ADMIN:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin);
+ break;
+ case PROMPT_REASON_USER_REQUEST:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request);
+ break;
+ case PROMPT_REASON_PREPARE_FOR_UPDATE:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ case PROMPT_REASON_NONE:
+ break;
+ default:
+ mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+ break;
+ }
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (colorState != null) {
+ mSecurityMessageDisplay.setNextMessageColor(colorState);
+ }
+ mSecurityMessageDisplay.setMessage(message);
+ }
+
+ @Override
public void startAppearAnimation() {
enableClipping(false);
setAlpha(1f);
@@ -146,7 +467,12 @@ public class KeyguardPatternView extends KeyguardInputView
0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
- () -> enableClipping(true),
+ new Runnable() {
+ @Override
+ public void run() {
+ enableClipping(true);
+ }
+ },
this);
if (!TextUtils.isEmpty(mSecurityMessageDisplay.getText())) {
mAppearAnimationUtils.createAnimation(mSecurityMessageDisplay, 0,
@@ -158,9 +484,11 @@ public class KeyguardPatternView extends KeyguardInputView
}
}
- public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
- final Runnable finishRunnable) {
- float durationMultiplier = needsSlowUnlockTransition ? DISAPPEAR_MULTIPLIER_LOCKED : 1f;
+ @Override
+ public boolean startDisappearAnimation(final Runnable finishRunnable) {
+ float durationMultiplier = mKeyguardUpdateMonitor.needsSlowUnlockTransition()
+ ? DISAPPEAR_MULTIPLIER_LOCKED
+ : 1f;
mLockPatternView.clearPattern();
enableClipping(false);
setTranslationY(0);
@@ -169,8 +497,10 @@ public class KeyguardPatternView extends KeyguardInputView
-mDisappearAnimationUtils.getStartTranslation(),
mDisappearAnimationUtils.getInterpolator());
- DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
- ? mDisappearAnimationUtilsLocked : mDisappearAnimationUtils;
+ DisappearAnimationUtils disappearAnimationUtils = mKeyguardUpdateMonitor
+ .needsSlowUnlockTransition()
+ ? mDisappearAnimationUtilsLocked
+ : mDisappearAnimationUtils;
disappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
() -> {
enableClipping(true);
@@ -219,7 +549,7 @@ public class KeyguardPatternView extends KeyguardInputView
@Override
public CharSequence getTitle() {
- return getResources().getString(
+ return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pattern_unlock);
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
deleted file mode 100644
index 3db9db7be00c..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL;
-import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
-
-import android.content.res.ColorStateList;
-import android.os.AsyncTask;
-import android.os.CountDownTimer;
-import android.os.SystemClock;
-import android.view.View;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternChecker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.internal.widget.LockPatternView;
-import com.android.internal.widget.LockPatternView.Cell;
-import com.android.internal.widget.LockscreenCredential;
-import com.android.keyguard.EmergencyButton.EmergencyButtonCallback;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-
-import java.util.List;
-
-public class KeyguardPatternViewController
- extends KeyguardInputViewController<KeyguardPatternView> {
-
- // how many cells the user has to cross before we poke the wakelock
- private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
-
- // how long before we clear the wrong pattern
- private static final int PATTERN_CLEAR_TIMEOUT_MS = 2000;
-
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final LockPatternUtils mLockPatternUtils;
- private final LatencyTracker mLatencyTracker;
- private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
-
- private KeyguardMessageAreaController mMessageAreaController;
- private LockPatternView mLockPatternView;
- private CountDownTimer mCountdownTimer;
- private AsyncTask<?, ?, ?> mPendingLockCheck;
-
- private EmergencyButtonCallback mEmergencyButtonCallback = new EmergencyButtonCallback() {
- @Override
- public void onEmergencyButtonClickedWhenInCall() {
- getKeyguardSecurityCallback().reset();
- }
- };
-
- /**
- * Useful for clearing out the wrong pattern after a delay
- */
- private Runnable mCancelPatternRunnable = new Runnable() {
- @Override
- public void run() {
- mLockPatternView.clearPattern();
- }
- };
-
- private class UnlockPatternListener implements LockPatternView.OnPatternListener {
-
- @Override
- public void onPatternStart() {
- mLockPatternView.removeCallbacks(mCancelPatternRunnable);
- mMessageAreaController.setMessage("");
- }
-
- @Override
- public void onPatternCleared() {
- }
-
- @Override
- public void onPatternCellAdded(List<Cell> pattern) {
- getKeyguardSecurityCallback().userActivity();
- getKeyguardSecurityCallback().onUserInput();
- }
-
- @Override
- public void onPatternDetected(final List<LockPatternView.Cell> pattern) {
- mKeyguardUpdateMonitor.setCredentialAttempted();
- mLockPatternView.disableInput();
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- }
-
- final int userId = KeyguardUpdateMonitor.getCurrentUser();
- if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
- mLockPatternView.enableInput();
- onPatternChecked(userId, false, 0, false /* not valid - too short */);
- return;
- }
-
- mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL);
- mLatencyTracker.onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- mPendingLockCheck = LockPatternChecker.checkCredential(
- mLockPatternUtils,
- LockscreenCredential.createPattern(pattern),
- userId,
- new LockPatternChecker.OnCheckCallback() {
-
- @Override
- public void onEarlyMatched() {
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL);
- onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
- true /* isValidPattern */);
- }
-
- @Override
- public void onChecked(boolean matched, int timeoutMs) {
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- mLockPatternView.enableInput();
- mPendingLockCheck = null;
- if (!matched) {
- onPatternChecked(userId, false /* matched */, timeoutMs,
- true /* isValidPattern */);
- }
- }
-
- @Override
- public void onCancelled() {
- // We already got dismissed with the early matched callback, so we
- // cancelled the check. However, we still need to note down the latency.
- mLatencyTracker.onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);
- }
- });
- if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
- getKeyguardSecurityCallback().userActivity();
- getKeyguardSecurityCallback().onUserInput();
- }
- }
-
- private void onPatternChecked(int userId, boolean matched, int timeoutMs,
- boolean isValidPattern) {
- boolean dismissKeyguard = KeyguardUpdateMonitor.getCurrentUser() == userId;
- if (matched) {
- getKeyguardSecurityCallback().reportUnlockAttempt(userId, true, 0);
- if (dismissKeyguard) {
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
- getKeyguardSecurityCallback().dismiss(true, userId);
- }
- } else {
- mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
- if (isValidPattern) {
- getKeyguardSecurityCallback().reportUnlockAttempt(userId, false, timeoutMs);
- if (timeoutMs > 0) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- userId, timeoutMs);
- handleAttemptLockout(deadline);
- }
- }
- if (timeoutMs == 0) {
- mMessageAreaController.setMessage(R.string.kg_wrong_pattern);
- mLockPatternView.postDelayed(mCancelPatternRunnable, PATTERN_CLEAR_TIMEOUT_MS);
- }
- }
- }
- }
-
- protected KeyguardPatternViewController(KeyguardPatternView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode,
- LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- LatencyTracker latencyTracker,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
- super(view, securityMode, keyguardSecurityCallback);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mLockPatternUtils = lockPatternUtils;
- mLatencyTracker = latencyTracker;
- mMessageAreaControllerFactory = messageAreaControllerFactory;
- KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
- mMessageAreaController = mMessageAreaControllerFactory.create(kma);
- mLockPatternView = mView.findViewById(R.id.lockPatternView);
- }
-
- @Override
- public void init() {
- super.init();
- mMessageAreaController.init();
- }
-
- @Override
- protected void onViewAttached() {
- mLockPatternView.setOnPatternListener(new UnlockPatternListener());
- mLockPatternView.setSaveEnabled(false);
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
- KeyguardUpdateMonitor.getCurrentUser()));
- // vibrate mode will be the same for the life of this screen
- mLockPatternView.setTactileFeedbackEnabled(mLockPatternUtils.isTactileFeedbackEnabled());
-
- EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
- if (button != null) {
- button.setCallback(mEmergencyButtonCallback);
- }
-
- View cancelBtn = mView.findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- getKeyguardSecurityCallback().reset();
- getKeyguardSecurityCallback().onCancelClicked();
- });
- }
- }
-
- @Override
- protected void onViewDetached() {
- super.onViewDetached();
- mLockPatternView.setOnPatternListener(null);
- EmergencyButton button = mView.findViewById(R.id.emergency_call_button);
- if (button != null) {
- button.setCallback(null);
- }
- View cancelBtn = mView.findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(null);
- }
- }
-
- @Override
- public void reset() {
- // reset lock pattern
- mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(
- KeyguardUpdateMonitor.getCurrentUser()));
- mLockPatternView.enableInput();
- mLockPatternView.setEnabled(true);
- mLockPatternView.clearPattern();
-
- // if the user is currently locked out, enforce it.
- long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- if (deadline != 0) {
- handleAttemptLockout(deadline);
- } else {
- displayDefaultSecurityMessage();
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (mCountdownTimer != null) {
- mCountdownTimer.cancel();
- mCountdownTimer = null;
- }
-
- if (mPendingLockCheck != null) {
- mPendingLockCheck.cancel(false);
- mPendingLockCheck = null;
- }
- displayDefaultSecurityMessage();
- }
-
- @Override
- public boolean needsInput() {
- return false;
- }
-
- @Override
- public void showPromptReason(int reason) {
- /// TODO: move all this logic into the MessageAreaController?
- switch (reason) {
- case PROMPT_REASON_RESTART:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_restart_pattern);
- break;
- case PROMPT_REASON_TIMEOUT:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- case PROMPT_REASON_DEVICE_ADMIN:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_device_admin);
- break;
- case PROMPT_REASON_USER_REQUEST:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_user_request);
- break;
- case PROMPT_REASON_PREPARE_FOR_UPDATE:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- case PROMPT_REASON_NONE:
- break;
- default:
- mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
- break;
- }
- }
-
- @Override
- public void showMessage(CharSequence message, ColorStateList colorState) {
- if (colorState != null) {
- mMessageAreaController.setNextMessageColor(colorState);
- }
- mMessageAreaController.setMessage(message);
- }
-
- @Override
- public void startAppearAnimation() {
- super.startAppearAnimation();
- }
-
- @Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return mView.startDisappearAnimation(
- mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
- }
-
- private void displayDefaultSecurityMessage() {
- mMessageAreaController.setMessage("");
- }
-
- private void handleAttemptLockout(long elapsedRealtimeDeadline) {
- mLockPatternView.clearPattern();
- mLockPatternView.setEnabled(false);
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long secondsInFuture = (long) Math.ceil(
- (elapsedRealtimeDeadline - elapsedRealtime) / 1000.0);
- mCountdownTimer = new CountDownTimer(secondsInFuture * 1000, 1000) {
-
- @Override
- public void onTick(long millisUntilFinished) {
- final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mMessageAreaController.setMessage(mView.getResources().getQuantityString(
- R.plurals.kg_too_many_failed_attempts_countdown,
- secondsRemaining, secondsRemaining));
- }
-
- @Override
- public void onFinish() {
- mLockPatternView.setEnabled(true);
- displayDefaultSecurityMessage();
- }
-
- }.start();
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 7fa43116a7b1..c7f27cf8a71a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -16,17 +16,11 @@
package com.android.keyguard;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
-
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.LockscreenCredential;
@@ -35,12 +29,22 @@ import com.android.systemui.R;
/**
* A Pin based Keyguard input view
*/
-public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView {
+public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
+ implements View.OnKeyListener, View.OnTouchListener {
protected PasswordTextView mPasswordEntry;
private View mOkButton;
private View mDeleteButton;
- private View[] mButtons = new View[10];
+ private View mButton0;
+ private View mButton1;
+ private View mButton2;
+ private View mButton3;
+ private View mButton4;
+ private View mButton5;
+ private View mButton6;
+ private View mButton7;
+ private View mButton8;
+ private View mButton9;
public KeyguardPinBasedInputView(Context context) {
this(context, null);
@@ -58,6 +62,7 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
protected void resetState() {
+ setPasswordEntryEnabled(true);
}
@Override
@@ -81,10 +86,10 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (KeyEvent.isConfirmKey(keyCode)) {
- mOkButton.performClick();
+ performClick(mOkButton);
return true;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
- mDeleteButton.performClick();
+ performClick(mDeleteButton);
return true;
}
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
@@ -120,9 +125,42 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
}
}
+ private void performClick(View view) {
+ view.performClick();
+ }
+
private void performNumberClick(int number) {
- if (number >= 0 && number <= 9) {
- mButtons[number].performClick();
+ switch (number) {
+ case 0:
+ performClick(mButton0);
+ break;
+ case 1:
+ performClick(mButton1);
+ break;
+ case 2:
+ performClick(mButton2);
+ break;
+ case 3:
+ performClick(mButton3);
+ break;
+ case 4:
+ performClick(mButton4);
+ break;
+ case 5:
+ performClick(mButton5);
+ break;
+ case 6:
+ performClick(mButton6);
+ break;
+ case 7:
+ performClick(mButton7);
+ break;
+ case 8:
+ performClick(mButton8);
+ break;
+ case 9:
+ performClick(mButton9);
+ break;
}
}
@@ -139,31 +177,94 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView
@Override
protected void onFinishInflate() {
mPasswordEntry = findViewById(getPasswordTextViewId());
+ mPasswordEntry.setOnKeyListener(this);
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
+ mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() {
+ @Override
+ public void onUserActivity() {
+ onUserInput();
+ }
+ });
+
mOkButton = findViewById(R.id.key_enter);
+ if (mOkButton != null) {
+ mOkButton.setOnTouchListener(this);
+ mOkButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mPasswordEntry.isEnabled()) {
+ verifyPasswordAndUnlock();
+ }
+ }
+ });
+ mOkButton.setOnHoverListener(new LiftToActivateListener(getContext()));
+ }
mDeleteButton = findViewById(R.id.delete_button);
mDeleteButton.setVisibility(View.VISIBLE);
+ mDeleteButton.setOnTouchListener(this);
+ mDeleteButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ mPasswordEntry.deleteLastChar();
+ }
+ }
+ });
+ mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ // check for time-based lockouts
+ if (mPasswordEntry.isEnabled()) {
+ resetPasswordText(true /* animate */, true /* announce */);
+ }
+ doHapticKeyClick();
+ return true;
+ }
+ });
- mButtons[0] = findViewById(R.id.key0);
- mButtons[1] = findViewById(R.id.key1);
- mButtons[2] = findViewById(R.id.key2);
- mButtons[3] = findViewById(R.id.key3);
- mButtons[4] = findViewById(R.id.key4);
- mButtons[5] = findViewById(R.id.key5);
- mButtons[6] = findViewById(R.id.key6);
- mButtons[7] = findViewById(R.id.key7);
- mButtons[8] = findViewById(R.id.key8);
- mButtons[9] = findViewById(R.id.key9);
+ mButton0 = findViewById(R.id.key0);
+ mButton1 = findViewById(R.id.key1);
+ mButton2 = findViewById(R.id.key2);
+ mButton3 = findViewById(R.id.key3);
+ mButton4 = findViewById(R.id.key4);
+ mButton5 = findViewById(R.id.key5);
+ mButton6 = findViewById(R.id.key6);
+ mButton7 = findViewById(R.id.key7);
+ mButton8 = findViewById(R.id.key8);
+ mButton9 = findViewById(R.id.key9);
mPasswordEntry.requestFocus();
super.onFinishInflate();
}
@Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ mPasswordEntry.requestFocus();
+ }
+
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ doHapticKeyClick();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ return onKeyDown(keyCode, event);
+ }
+ return false;
+ }
+
+ @Override
public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_pin_unlock);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
deleted file mode 100644
index 4d0ebfffbe04..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnKeyListener;
-import android.view.View.OnTouchListener;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-
-public abstract class KeyguardPinBasedInputViewController<T extends KeyguardPinBasedInputView>
- extends KeyguardAbsKeyInputViewController<T> {
-
- private final LiftToActivateListener mLiftToActivateListener;
- protected PasswordTextView mPasswordEntry;
-
- private final OnKeyListener mOnKeyListener = (v, keyCode, event) -> {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- return mView.onKeyDown(keyCode, event);
- }
- return false;
- };
-
- private final OnTouchListener mOnTouchListener = (v, event) -> {
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
- mView.doHapticKeyClick();
- }
- return false;
- };
-
- protected KeyguardPinBasedInputViewController(T view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode,
- LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener) {
- super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker);
- mLiftToActivateListener = liftToActivateListener;
- mPasswordEntry = mView.findViewById(mView.getPasswordTextViewId());
- }
-
- @Override
- protected void onViewAttached() {
- super.onViewAttached();
-
- mPasswordEntry.setOnKeyListener(mOnKeyListener);
- mPasswordEntry.setUserActivityListener(this::onUserInput);
-
- View deleteButton = mView.findViewById(R.id.delete_button);
- deleteButton.setOnTouchListener(mOnTouchListener);
- deleteButton.setOnClickListener(v -> {
- // check for time-based lockouts
- if (mPasswordEntry.isEnabled()) {
- mPasswordEntry.deleteLastChar();
- }
- });
- deleteButton.setOnLongClickListener(v -> {
- // check for time-based lockouts
- if (mPasswordEntry.isEnabled()) {
- mView.resetPasswordText(true /* animate */, true /* announce */);
- }
- mView.doHapticKeyClick();
- return true;
- });
-
- View okButton = mView.findViewById(R.id.key_enter);
- if (okButton != null) {
- okButton.setOnTouchListener(mOnTouchListener);
- okButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mPasswordEntry.isEnabled()) {
- verifyPasswordAndUnlock();
- }
- }
- });
- okButton.setOnHoverListener(mLiftToActivateListener);
- }
- }
-
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- mPasswordEntry.requestFocus();
- }
-
- @Override
- void resetState() {
- mView.setPasswordEntryEnabled(true);
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
deleted file mode 100644
index 6769436be8ef..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.view.View;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-
-public class KeyguardPinViewController
- extends KeyguardPinBasedInputViewController<KeyguardPINView> {
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-
- protected KeyguardPinViewController(KeyguardPINView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode, LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener) {
- super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- }
-
- @Override
- protected void onViewAttached() {
- super.onViewAttached();
-
- View cancelBtn = mView.findViewById(R.id.cancel_button);
- if (cancelBtn != null) {
- cancelBtn.setOnClickListener(view -> {
- getKeyguardSecurityCallback().reset();
- getKeyguardSecurityCallback().onCancelClicked();
- });
- }
- }
-
- @Override
- void resetState() {
- super.resetState();
- mMessageAreaController.setMessage("");
- }
-
- @Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return mView.startDisappearAnimation(
- mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b62ea6bc2ff6..81d37a830f8f 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -19,6 +19,8 @@ import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
+import static com.android.systemui.DejankUtils.whitelistIpcs;
+
import static java.lang.Integer.max;
import android.animation.Animator;
@@ -26,14 +28,25 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.ColorStateList;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.metrics.LogMaker;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
+import android.util.Slog;
import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
@@ -48,30 +61,42 @@ import androidx.annotation.VisibleForTesting;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.logging.UiEventLoggerImpl;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.InjectionInflationController;
import java.util.List;
-public class KeyguardSecurityContainer extends FrameLayout {
- static final int USER_TYPE_PRIMARY = 1;
- static final int USER_TYPE_WORK_PROFILE = 2;
- static final int USER_TYPE_SECONDARY_USER = 3;
+public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
+ private static final boolean DEBUG = KeyguardConstants.DEBUG;
+ private static final String TAG = "KeyguardSecurityView";
+
+ private static final int USER_TYPE_PRIMARY = 1;
+ private static final int USER_TYPE_WORK_PROFILE = 2;
+ private static final int USER_TYPE_SECONDARY_USER = 3;
// Bouncer is dismissed due to no security.
- static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
+ private static final int BOUNCER_DISMISS_NONE_SECURITY = 0;
// Bouncer is dismissed due to pin, password or pattern entered.
- static final int BOUNCER_DISMISS_PASSWORD = 1;
+ private static final int BOUNCER_DISMISS_PASSWORD = 1;
// Bouncer is dismissed due to biometric (face, fingerprint or iris) authenticated.
- static final int BOUNCER_DISMISS_BIOMETRIC = 2;
+ private static final int BOUNCER_DISMISS_BIOMETRIC = 2;
// Bouncer is dismissed due to extended access granted.
- static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
+ private static final int BOUNCER_DISMISS_EXTENDED_ACCESS = 3;
// Bouncer is dismissed due to sim card unlock code entered.
- static final int BOUNCER_DISMISS_SIM = 4;
+ private static final int BOUNCER_DISMISS_SIM = 4;
// Make the view move slower than the finger, as if the spring were applying force.
private static final float TOUCH_Y_MULTIPLIER = 0.25f;
@@ -80,23 +105,36 @@ public class KeyguardSecurityContainer extends FrameLayout {
// How much to scale the default slop by, to avoid accidental drags.
private static final float SLOP_SCALE = 4f;
+ private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
+
private static final long IME_DISAPPEAR_DURATION_MS = 125;
+ private KeyguardSecurityModel mSecurityModel;
+ private LockPatternUtils mLockPatternUtils;
+
@VisibleForTesting
KeyguardSecurityViewFlipper mSecurityViewFlipper;
+ private boolean mIsVerifyUnlockOnly;
+ private SecurityMode mCurrentSecuritySelection = SecurityMode.Invalid;
+ private KeyguardSecurityView mCurrentSecurityView;
+ private SecurityCallback mSecurityCallback;
private AlertDialog mAlertDialog;
+ private InjectionInflationController mInjectionInflationController;
private boolean mSwipeUpToRetry;
+ private AdminSecondaryLockScreenController mSecondaryLockScreenController;
private final ViewConfiguration mViewConfiguration;
private final SpringAnimation mSpringAnimation;
private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+ private final KeyguardUpdateMonitor mUpdateMonitor;
+ private final KeyguardStateController mKeyguardStateController;
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private float mLastTouchY = -1;
private int mActivePointerId = -1;
private boolean mIsDragging;
private float mStartTouchY = -1;
private boolean mDisappearAnimRunning;
- private SwipeListener mSwipeListener;
private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
@@ -148,22 +186,19 @@ public class KeyguardSecurityContainer extends FrameLayout {
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
- boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
- void userActivity();
- void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
+ public boolean dismiss(boolean authenticated, int targetUserId,
+ boolean bypassSecondaryLockScreen);
+ public void userActivity();
+ public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
/**
* @param strongAuth wheher the user has authenticated with strong authentication like
* pattern, password or PIN but not by trust agents or fingerprint
* @param targetUserId a user that needs to be the foreground user at the finish completion.
*/
- void finish(boolean strongAuth, int targetUserId);
- void reset();
- void onCancelClicked();
- }
-
- public interface SwipeListener {
- void onSwipeUp();
+ public void finish(boolean strongAuth, int targetUserId);
+ public void reset();
+ public void onCancelClicked();
}
@VisibleForTesting
@@ -214,24 +249,52 @@ public class KeyguardSecurityContainer extends FrameLayout {
public KeyguardSecurityContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ mSecurityModel = Dependency.get(KeyguardSecurityModel.class);
+ mLockPatternUtils = new LockPatternUtils(context);
+ mUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
mSpringAnimation = new SpringAnimation(this, DynamicAnimation.Y);
+ mInjectionInflationController = new InjectionInflationController(
+ SystemUIFactory.getInstance().getSysUIComponent().createViewInstanceCreatorFactory());
mViewConfiguration = ViewConfiguration.get(context);
+ mKeyguardStateController = Dependency.get(KeyguardStateController.class);
+ mSecondaryLockScreenController = new AdminSecondaryLockScreenController(context, this,
+ mUpdateMonitor, mCallback, new Handler(Looper.myLooper()));
+ }
+
+ public void setSecurityCallback(SecurityCallback callback) {
+ mSecurityCallback = callback;
}
- void onResume(SecurityMode securityMode, boolean faceAuthEnabled) {
+ @Override
+ public void onResume(int reason) {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ getSecurityView(mCurrentSecuritySelection).onResume(reason);
+ }
mSecurityViewFlipper.setWindowInsetsAnimationCallback(mWindowInsetsAnimationCallback);
- updateBiometricRetry(securityMode, faceAuthEnabled);
+ updateBiometricRetry();
}
+ @Override
public void onPause() {
if (mAlertDialog != null) {
mAlertDialog.dismiss();
mAlertDialog = null;
}
+ mSecondaryLockScreenController.hide();
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ getSecurityView(mCurrentSecuritySelection).onPause();
+ }
mSecurityViewFlipper.setWindowInsetsAnimationCallback(null);
}
@Override
+ public void onStartingToHide() {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ getSecurityView(mCurrentSecuritySelection).onStartingToHide();
+ }
+ }
+
+ @Override
public boolean shouldDelayChildPressedState() {
return true;
}
@@ -253,12 +316,13 @@ public class KeyguardSecurityContainer extends FrameLayout {
return false;
}
// Avoid dragging the pattern view
- if (mSecurityViewFlipper.getSecurityView().disallowInterceptTouch(event)) {
+ if (mCurrentSecurityView.disallowInterceptTouch(event)) {
return false;
}
int index = event.findPointerIndex(mActivePointerId);
float touchSlop = mViewConfiguration.getScaledTouchSlop() * SLOP_SCALE;
- if (index != -1 && mStartTouchY - event.getY(index) > touchSlop) {
+ if (mCurrentSecurityView != null && index != -1
+ && mStartTouchY - event.getY(index) > touchSlop) {
mIsDragging = true;
return true;
}
@@ -306,28 +370,31 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
if (action == MotionEvent.ACTION_UP) {
if (-getTranslationY() > TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- MIN_DRAG_SIZE, getResources().getDisplayMetrics())) {
- if (mSwipeListener != null) {
- mSwipeListener.onSwipeUp();
- }
+ MIN_DRAG_SIZE, getResources().getDisplayMetrics())
+ && !mUpdateMonitor.isFaceDetectionRunning()) {
+ mUpdateMonitor.requestFaceAuth();
+ mCallback.userActivity();
+ showMessage(null, null);
}
}
return true;
}
- void setSwipeListener(SwipeListener swipeListener) {
- mSwipeListener = swipeListener;
- }
-
private void startSpringAnimation(float startVelocity) {
mSpringAnimation
.setStartVelocity(startVelocity)
.animateToFinalPosition(0);
}
- public void startDisappearAnimation(SecurityMode securitySelection) {
+ public void startAppearAnimation() {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ getSecurityView(mCurrentSecuritySelection).startAppearAnimation();
+ }
+ }
+
+ public boolean startDisappearAnimation(Runnable onFinishRunnable) {
mDisappearAnimRunning = true;
- if (securitySelection == SecurityMode.Password) {
+ if (mCurrentSecuritySelection == SecurityMode.Password) {
mSecurityViewFlipper.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
IME_DISAPPEAR_DURATION_MS,
Interpolators.LINEAR, null, new WindowInsetsAnimationControlListener() {
@@ -372,13 +439,19 @@ public class KeyguardSecurityContainer extends FrameLayout {
}
});
}
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ return getSecurityView(mCurrentSecuritySelection).startDisappearAnimation(
+ onFinishRunnable);
+ }
+ return false;
}
/**
* Enables/disables swipe up to retry on the bouncer.
*/
- private void updateBiometricRetry(SecurityMode securityMode, boolean faceAuthEnabled) {
- mSwipeUpToRetry = faceAuthEnabled
+ private void updateBiometricRetry() {
+ SecurityMode securityMode = getSecurityMode();
+ mSwipeUpToRetry = mKeyguardStateController.isFaceAuthEnabled()
&& securityMode != SecurityMode.SimPin
&& securityMode != SecurityMode.SimPuk
&& securityMode != SecurityMode.None;
@@ -388,11 +461,53 @@ public class KeyguardSecurityContainer extends FrameLayout {
return mSecurityViewFlipper.getTitle();
}
+ @VisibleForTesting
+ protected KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
+ final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+ KeyguardSecurityView view = null;
+ final int children = mSecurityViewFlipper.getChildCount();
+ for (int child = 0; child < children; child++) {
+ if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
+ view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
+ break;
+ }
+ }
+ int layoutId = getLayoutIdFor(securityMode);
+ if (view == null && layoutId != 0) {
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
+ if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
+ View v = mInjectionInflationController.injectable(inflater)
+ .inflate(layoutId, mSecurityViewFlipper, false);
+ mSecurityViewFlipper.addView(v);
+ updateSecurityView(v);
+ view = (KeyguardSecurityView)v;
+ view.reset();
+ }
+
+ return view;
+ }
+
+ private void updateSecurityView(View view) {
+ if (view instanceof KeyguardSecurityView) {
+ KeyguardSecurityView ksv = (KeyguardSecurityView) view;
+ ksv.setKeyguardCallback(mCallback);
+ ksv.setLockPatternUtils(mLockPatternUtils);
+ } else {
+ Log.w(TAG, "View " + view + " is not a KeyguardSecurityView");
+ }
+ }
@Override
public void onFinishInflate() {
super.onFinishInflate();
mSecurityViewFlipper = findViewById(R.id.view_flipper);
+ mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
+ }
+
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
+ mSecurityModel.setLockPatternUtils(utils);
+ mSecurityViewFlipper.setLockPatternUtils(mLockPatternUtils);
}
@Override
@@ -424,12 +539,11 @@ public class KeyguardSecurityContainer extends FrameLayout {
mAlertDialog.show();
}
- void showTimeoutDialog(int userId, int timeoutMs, LockPatternUtils lockPatternUtils,
- SecurityMode securityMode) {
- int timeoutInSeconds = timeoutMs / 1000;
+ private void showTimeoutDialog(int userId, int timeoutMs) {
+ int timeoutInSeconds = (int) timeoutMs / 1000;
int messageId = 0;
- switch (securityMode) {
+ switch (mSecurityModel.getSecurityMode(userId)) {
case Pattern:
messageId = R.string.kg_too_many_failed_pattern_attempts_dialog_message;
break;
@@ -449,13 +563,13 @@ public class KeyguardSecurityContainer extends FrameLayout {
if (messageId != 0) {
final String message = mContext.getString(messageId,
- lockPatternUtils.getCurrentFailedPasswordAttempts(userId),
+ mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
timeoutInSeconds);
showDialog(null, message);
}
}
- void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
+ private void showAlmostAtWipeDialog(int attempts, int remaining, int userType) {
String message = null;
switch (userType) {
case USER_TYPE_PRIMARY:
@@ -474,7 +588,7 @@ public class KeyguardSecurityContainer extends FrameLayout {
showDialog(null, message);
}
- void showWipeDialog(int attempts, int userType) {
+ private void showWipeDialog(int attempts, int userType) {
String message = null;
switch (userType) {
case USER_TYPE_PRIMARY:
@@ -493,8 +607,358 @@ public class KeyguardSecurityContainer extends FrameLayout {
showDialog(null, message);
}
+ private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
+ // +1 for this time
+ final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
+
+ if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
+
+ final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
+ final int failedAttemptsBeforeWipe =
+ dpm.getMaximumFailedPasswordsForWipe(null, userId);
+
+ final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
+ (failedAttemptsBeforeWipe - failedAttempts)
+ : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
+ if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
+ // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
+ // N attempts. Once we get below the grace period, we post this dialog every time as a
+ // clear warning until the deletion fires.
+ // Check which profile has the strictest policy for failed password attempts
+ final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
+ int userType = USER_TYPE_PRIMARY;
+ if (expiringUser == userId) {
+ // TODO: http://b/23522538
+ if (expiringUser != UserHandle.USER_SYSTEM) {
+ userType = USER_TYPE_SECONDARY_USER;
+ }
+ } else if (expiringUser != UserHandle.USER_NULL) {
+ userType = USER_TYPE_WORK_PROFILE;
+ } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
+ if (remainingBeforeWipe > 0) {
+ showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
+ } else {
+ // Too many attempts. The device will be wiped shortly.
+ Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
+ showWipeDialog(failedAttempts, userType);
+ }
+ }
+ mLockPatternUtils.reportFailedPasswordAttempt(userId);
+ if (timeoutMs > 0) {
+ mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
+ showTimeoutDialog(userId, timeoutMs);
+ }
+ }
+
+ /**
+ * Shows the primary security screen for the user. This will be either the multi-selector
+ * or the user's security method.
+ * @param turningOff true if the device is being turned off
+ */
+ void showPrimarySecurityScreen(boolean turningOff) {
+ SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
+ KeyguardUpdateMonitor.getCurrentUser()));
+ if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
+ showSecurityScreen(securityMode);
+ }
+
+ /**
+ * Shows the next security screen if there is one.
+ * @param authenticated true if the user entered the correct authentication
+ * @param targetUserId a user that needs to be the foreground user at the finish (if called)
+ * completion.
+ * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
+ * secondary lock screen requirement, if any.
+ * @return true if keyguard is done
+ */
+ boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
+ boolean bypassSecondaryLockScreen) {
+ if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
+ boolean finish = false;
+ boolean strongAuth = false;
+ int eventSubtype = -1;
+ BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
+ if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
+ } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
+ } else if (SecurityMode.None == mCurrentSecuritySelection) {
+ SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+ if (SecurityMode.None == securityMode) {
+ finish = true; // no security required
+ eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
+ } else {
+ showSecurityScreen(securityMode); // switch to the alternate security view
+ }
+ } else if (authenticated) {
+ switch (mCurrentSecuritySelection) {
+ case Pattern:
+ case Password:
+ case PIN:
+ strongAuth = true;
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_PASSWORD;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
+ break;
+
+ case SimPin:
+ case SimPuk:
+ // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
+ SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+ if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())) {
+ finish = true;
+ eventSubtype = BOUNCER_DISMISS_SIM;
+ uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
+ } else {
+ showSecurityScreen(securityMode);
+ }
+ break;
+
+ default:
+ Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
+ showPrimarySecurityScreen(false);
+ break;
+ }
+ }
+ // Check for device admin specified additional security measures.
+ if (finish && !bypassSecondaryLockScreen) {
+ Intent secondaryLockscreenIntent =
+ mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
+ if (secondaryLockscreenIntent != null) {
+ mSecondaryLockScreenController.show(secondaryLockscreenIntent);
+ return false;
+ }
+ }
+ if (eventSubtype != -1) {
+ mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
+ .setType(MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
+ }
+ if (uiEvent != BouncerUiEvent.UNKNOWN) {
+ sUiEventLogger.log(uiEvent);
+ }
+ if (finish) {
+ mSecurityCallback.finish(strongAuth, targetUserId);
+ }
+ return finish;
+ }
+
+ /**
+ * Switches to the given security view unless it's already being shown, in which case
+ * this is a no-op.
+ *
+ * @param securityMode
+ */
+ private void showSecurityScreen(SecurityMode securityMode) {
+ if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
+
+ if (securityMode == mCurrentSecuritySelection) return;
+
+ KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
+ KeyguardSecurityView newView = getSecurityView(securityMode);
+
+ // Emulate Activity life cycle
+ if (oldView != null) {
+ oldView.onPause();
+ oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
+ }
+ if (securityMode != SecurityMode.None) {
+ newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
+ newView.setKeyguardCallback(mCallback);
+ }
+
+ // Find and show this child.
+ final int childCount = mSecurityViewFlipper.getChildCount();
+
+ final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
+ for (int i = 0; i < childCount; i++) {
+ if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
+ mSecurityViewFlipper.setDisplayedChild(i);
+ break;
+ }
+ }
+
+ mCurrentSecuritySelection = securityMode;
+ mCurrentSecurityView = newView;
+ mSecurityCallback.onSecurityModeChanged(securityMode,
+ securityMode != SecurityMode.None && newView.needsInput());
+ }
+
+ private KeyguardSecurityCallback mCallback = new KeyguardSecurityCallback() {
+ public void userActivity() {
+ if (mSecurityCallback != null) {
+ mSecurityCallback.userActivity();
+ }
+ }
+
+ @Override
+ public void onUserInput() {
+ mUpdateMonitor.cancelFaceAuth();
+ }
+
+ @Override
+ public void dismiss(boolean authenticated, int targetId) {
+ dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
+ }
+
+ @Override
+ public void dismiss(boolean authenticated, int targetId,
+ boolean bypassSecondaryLockScreen) {
+ mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
+ }
+
+ public boolean isVerifyUnlockOnly() {
+ return mIsVerifyUnlockOnly;
+ }
+
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
+ if (success) {
+ SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
+ mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
+ // Force a garbage collection in an attempt to erase any lockscreen password left in
+ // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
+ // dismiss animation janky.
+ ThreadUtils.postOnBackgroundThread(() -> {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException ignored) { }
+ Runtime.getRuntime().gc();
+ });
+ } else {
+ SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
+ SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
+ KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs);
+ }
+ mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
+ .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
+ sUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
+ : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
+ }
+
+ public void reset() {
+ mSecurityCallback.reset();
+ }
+
+ public void onCancelClicked() {
+ mSecurityCallback.onCancelClicked();
+ }
+ };
+
+ // The following is used to ignore callbacks from SecurityViews that are no longer current
+ // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
+ // state for the current security method.
+ private KeyguardSecurityCallback mNullCallback = new KeyguardSecurityCallback() {
+ @Override
+ public void userActivity() { }
+ @Override
+ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
+ @Override
+ public boolean isVerifyUnlockOnly() { return false; }
+ @Override
+ public void dismiss(boolean securityVerified, int targetUserId) { }
+ @Override
+ public void dismiss(boolean authenticated, int targetId,
+ boolean bypassSecondaryLockScreen) { }
+ @Override
+ public void onUserInput() { }
+ @Override
+ public void reset() {}
+ };
+
+ private int getSecurityViewIdForMode(SecurityMode securityMode) {
+ switch (securityMode) {
+ case Pattern: return R.id.keyguard_pattern_view;
+ case PIN: return R.id.keyguard_pin_view;
+ case Password: return R.id.keyguard_password_view;
+ case SimPin: return R.id.keyguard_sim_pin_view;
+ case SimPuk: return R.id.keyguard_sim_puk_view;
+ }
+ return 0;
+ }
+
+ @VisibleForTesting
+ public int getLayoutIdFor(SecurityMode securityMode) {
+ switch (securityMode) {
+ case Pattern: return R.layout.keyguard_pattern_view;
+ case PIN: return R.layout.keyguard_pin_view;
+ case Password: return R.layout.keyguard_password_view;
+ case SimPin: return R.layout.keyguard_sim_pin_view;
+ case SimPuk: return R.layout.keyguard_sim_puk_view;
+ default:
+ return 0;
+ }
+ }
+
+ public SecurityMode getSecurityMode() {
+ return mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser());
+ }
+
+ public SecurityMode getCurrentSecurityMode() {
+ return mCurrentSecuritySelection;
+ }
+
+ public KeyguardSecurityView getCurrentSecurityView() {
+ return mCurrentSecurityView;
+ }
+
+ public void verifyUnlock() {
+ mIsVerifyUnlockOnly = true;
+ showSecurityScreen(getSecurityMode());
+ }
+
+ public SecurityMode getCurrentSecuritySelection() {
+ return mCurrentSecuritySelection;
+ }
+
+ public void dismiss(boolean authenticated, int targetUserId) {
+ mCallback.dismiss(authenticated, targetUserId);
+ }
+
+ public boolean needsInput() {
+ return mSecurityViewFlipper.needsInput();
+ }
+
+ @Override
+ public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+ mSecurityViewFlipper.setKeyguardCallback(callback);
+ }
+
+ @Override
public void reset() {
+ mSecurityViewFlipper.reset();
mDisappearAnimRunning = false;
}
+
+ @Override
+ public KeyguardSecurityCallback getCallback() {
+ return mSecurityViewFlipper.getCallback();
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ if (reason != PROMPT_REASON_NONE) {
+ Log.i(TAG, "Strong auth required, reason: " + reason);
+ }
+ getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
+ }
+ }
+
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ if (mCurrentSecuritySelection != SecurityMode.None) {
+ getSecurityView(mCurrentSecuritySelection).showMessage(message, colorState);
+ }
+ }
+
+ @Override
+ public void showUsabilityHint() {
+ mSecurityViewFlipper.showUsabilityHint();
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 64676e55b038..17f25bd08ef4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -16,166 +16,33 @@
package com.android.keyguard;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_BIOMETRIC;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_EXTENDED_ACCESS;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_NONE_SECURITY;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_PASSWORD;
-import static com.android.keyguard.KeyguardSecurityContainer.BOUNCER_DISMISS_SIM;
-import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_PRIMARY;
-import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_SECONDARY_USER;
-import static com.android.keyguard.KeyguardSecurityContainer.USER_TYPE_WORK_PROFILE;
-import static com.android.systemui.DejankUtils.whitelistIpcs;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.Intent;
import android.content.res.ColorStateList;
-import android.metrics.LogMaker;
-import android.os.UserHandle;
-import android.util.Log;
-import android.util.Slog;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityContainer.BouncerUiEvent;
import com.android.keyguard.KeyguardSecurityContainer.SecurityCallback;
-import com.android.keyguard.KeyguardSecurityContainer.SwipeListener;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.settingslib.utils.ThreadUtils;
-import com.android.systemui.shared.system.SysUiStatsLog;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
/** Controller for {@link KeyguardSecurityContainer} */
-@KeyguardBouncerScope
-public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer>
- implements KeyguardSecurityView {
-
- private static final boolean DEBUG = KeyguardConstants.DEBUG;
- private static final String TAG = "KeyguardSecurityView";
+public class KeyguardSecurityContainerController extends ViewController<KeyguardSecurityContainer> {
- private final AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardSecurityModel mSecurityModel;
- private final MetricsLogger mMetricsLogger;
- private final UiEventLogger mUiEventLogger;
- private final KeyguardStateController mKeyguardStateController;
- private final KeyguardSecurityViewFlipperController mSecurityViewFlipperController;
-
- private SecurityCallback mSecurityCallback;
- private SecurityMode mCurrentSecurityMode = SecurityMode.Invalid;
-
- private KeyguardSecurityCallback mKeyguardSecurityCallback = new KeyguardSecurityCallback() {
- public void userActivity() {
- if (mSecurityCallback != null) {
- mSecurityCallback.userActivity();
- }
- }
-
- @Override
- public void onUserInput() {
- mUpdateMonitor.cancelFaceAuth();
- }
-
- @Override
- public void dismiss(boolean authenticated, int targetId) {
- dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
- }
-
- @Override
- public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) {
- mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
- }
-
- public boolean isVerifyUnlockOnly() {
- return false;
- }
-
- public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) {
- if (success) {
- SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
- SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
- mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
- // Force a garbage collection in an attempt to erase any lockscreen password left in
- // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
- // dismiss animation janky.
- ThreadUtils.postOnBackgroundThread(() -> {
- try {
- Thread.sleep(5000);
- } catch (InterruptedException ignored) { }
- Runtime.getRuntime().gc();
- });
- } else {
- SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
- SysUiStatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
- reportFailedUnlockAttempt(userId, timeoutMs);
- }
- mMetricsLogger.write(new LogMaker(MetricsEvent.BOUNCER)
- .setType(success ? MetricsEvent.TYPE_SUCCESS : MetricsEvent.TYPE_FAILURE));
- mUiEventLogger.log(success ? BouncerUiEvent.BOUNCER_PASSWORD_SUCCESS
- : BouncerUiEvent.BOUNCER_PASSWORD_FAILURE);
- }
-
- public void reset() {
- mSecurityCallback.reset();
- }
-
- public void onCancelClicked() {
- mSecurityCallback.onCancelClicked();
- }
- };
-
-
- private SwipeListener mSwipeListener = new SwipeListener() {
- @Override
- public void onSwipeUp() {
- if (!mUpdateMonitor.isFaceDetectionRunning()) {
- mUpdateMonitor.requestFaceAuth();
- mKeyguardSecurityCallback.userActivity();
- showMessage(null, null);
- }
- }
- };
+ private final KeyguardSecurityViewController.Factory mKeyguardSecurityViewControllerFactory;
@Inject
KeyguardSecurityContainerController(KeyguardSecurityContainer view,
- AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
LockPatternUtils lockPatternUtils,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- KeyguardSecurityModel keyguardSecurityModel,
- MetricsLogger metricsLogger,
- UiEventLogger uiEventLogger,
- KeyguardStateController keyguardStateController,
- KeyguardSecurityViewFlipperController securityViewFlipperController) {
+ KeyguardSecurityViewController.Factory keyguardSecurityViewControllerFactory) {
super(view);
mLockPatternUtils = lockPatternUtils;
- mUpdateMonitor = keyguardUpdateMonitor;
- mSecurityModel = keyguardSecurityModel;
- mMetricsLogger = metricsLogger;
- mUiEventLogger = uiEventLogger;
- mKeyguardStateController = keyguardStateController;
- mSecurityViewFlipperController = securityViewFlipperController;
- mAdminSecondaryLockScreenController = adminSecondaryLockScreenControllerFactory.create(
- mKeyguardSecurityCallback);
- }
-
- @Override
- public void init() {
- super.init();
- mSecurityViewFlipperController.init();
+ view.setLockPatternUtils(mLockPatternUtils);
+ mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
}
@Override
protected void onViewAttached() {
- mView.setSwipeListener(mSwipeListener);
}
@Override
@@ -184,270 +51,68 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
/** */
public void onPause() {
- mAdminSecondaryLockScreenController.hide();
- if (mCurrentSecurityMode != SecurityMode.None) {
- getCurrentSecurityController().onPause();
- }
mView.onPause();
}
-
- /**
- * Shows the primary security screen for the user. This will be either the multi-selector
- * or the user's security method.
- * @param turningOff true if the device is being turned off
- */
public void showPrimarySecurityScreen(boolean turningOff) {
- SecurityMode securityMode = whitelistIpcs(() -> mSecurityModel.getSecurityMode(
- KeyguardUpdateMonitor.getCurrentUser()));
- if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
- showSecurityScreen(securityMode);
+ mView.showPrimarySecurityScreen(turningOff);
}
- @Override
public void showPromptReason(int reason) {
- if (mCurrentSecurityMode != SecurityMode.None) {
- if (reason != PROMPT_REASON_NONE) {
- Log.i(TAG, "Strong auth required, reason: " + reason);
- }
- getCurrentSecurityController().showPromptReason(reason);
- }
+ mView.showPromptReason(reason);
}
public void showMessage(CharSequence message, ColorStateList colorState) {
- if (mCurrentSecurityMode != SecurityMode.None) {
- getCurrentSecurityController().showMessage(message, colorState);
- }
+ mView.showMessage(message, colorState);
}
- public SecurityMode getCurrentSecurityMode() {
- return mCurrentSecurityMode;
+ public SecurityMode getCurrentSecuritySelection() {
+ return mView.getCurrentSecuritySelection();
}
public void dismiss(boolean authenticated, int targetUserId) {
- mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
+ mView.dismiss(authenticated, targetUserId);
}
public void reset() {
mView.reset();
- mSecurityViewFlipperController.reset();
}
public CharSequence getTitle() {
return mView.getTitle();
}
- @Override
- public void onResume(int reason) {
- if (mCurrentSecurityMode != SecurityMode.None) {
- getCurrentSecurityController().onResume(reason);
- }
- mView.onResume(
- mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
- mKeyguardStateController.isFaceAuthEnabled());
+ public void onResume(int screenOn) {
+ mView.onResume(screenOn);
}
public void startAppearAnimation() {
- if (mCurrentSecurityMode != SecurityMode.None) {
- getCurrentSecurityController().startAppearAnimation();
- }
+ mView.startAppearAnimation();
}
public boolean startDisappearAnimation(Runnable onFinishRunnable) {
- mView.startDisappearAnimation(getCurrentSecurityMode());
-
- if (mCurrentSecurityMode != SecurityMode.None) {
- return getCurrentSecurityController().startDisappearAnimation(onFinishRunnable);
- }
-
- return false;
+ return mView.startDisappearAnimation(onFinishRunnable);
}
public void onStartingToHide() {
- if (mCurrentSecurityMode != SecurityMode.None) {
- getCurrentSecurityController().onStartingToHide();
- }
+ mView.onStartingToHide();
}
public void setSecurityCallback(SecurityCallback securityCallback) {
- mSecurityCallback = securityCallback;
+ mView.setSecurityCallback(securityCallback);
}
- /**
- * Shows the next security screen if there is one.
- * @param authenticated true if the user entered the correct authentication
- * @param targetUserId a user that needs to be the foreground user at the finish (if called)
- * completion.
- * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
- * secondary lock screen requirement, if any.
- * @return true if keyguard is done
- */
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
-
- if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
- boolean finish = false;
- boolean strongAuth = false;
- int eventSubtype = -1;
- BouncerUiEvent uiEvent = BouncerUiEvent.UNKNOWN;
- if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_EXTENDED_ACCESS;
- } else if (mUpdateMonitor.getUserUnlockedWithBiometric(targetUserId)) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_BIOMETRIC;
- } else if (SecurityMode.None == getCurrentSecurityMode()) {
- SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (SecurityMode.None == securityMode) {
- finish = true; // no security required
- eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_NONE_SECURITY;
- } else {
- showSecurityScreen(securityMode); // switch to the alternate security view
- }
- } else if (authenticated) {
- switch (getCurrentSecurityMode()) {
- case Pattern:
- case Password:
- case PIN:
- strongAuth = true;
- finish = true;
- eventSubtype = BOUNCER_DISMISS_PASSWORD;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_PASSWORD;
- break;
-
- case SimPin:
- case SimPuk:
- // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
- SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None && mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser())) {
- finish = true;
- eventSubtype = BOUNCER_DISMISS_SIM;
- uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
- } else {
- showSecurityScreen(securityMode);
- }
- break;
-
- default:
- Log.v(TAG, "Bad security screen " + getCurrentSecurityMode()
- + ", fail safe");
- showPrimarySecurityScreen(false);
- break;
- }
- }
- // Check for device admin specified additional security measures.
- if (finish && !bypassSecondaryLockScreen) {
- Intent secondaryLockscreenIntent =
- mUpdateMonitor.getSecondaryLockscreenRequirement(targetUserId);
- if (secondaryLockscreenIntent != null) {
- mAdminSecondaryLockScreenController.show(secondaryLockscreenIntent);
- return false;
- }
- }
- if (eventSubtype != -1) {
- mMetricsLogger.write(new LogMaker(MetricsProto.MetricsEvent.BOUNCER)
- .setType(MetricsProto.MetricsEvent.TYPE_DISMISS).setSubtype(eventSubtype));
- }
- if (uiEvent != BouncerUiEvent.UNKNOWN) {
- mUiEventLogger.log(uiEvent);
- }
- if (finish) {
- mSecurityCallback.finish(strongAuth, targetUserId);
- }
- return finish;
+ return mView.showNextSecurityScreenOrFinish(
+ authenticated, targetUserId, bypassSecondaryLockScreen);
}
public boolean needsInput() {
- return getCurrentSecurityController().needsInput();
- }
-
- /**
- * Switches to the given security view unless it's already being shown, in which case
- * this is a no-op.
- *
- * @param securityMode
- */
- @VisibleForTesting
- void showSecurityScreen(SecurityMode securityMode) {
- if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");
-
- if (securityMode == SecurityMode.Invalid || securityMode == mCurrentSecurityMode) {
- return;
- }
-
- KeyguardInputViewController<KeyguardInputView> oldView = getCurrentSecurityController();
-
- // Emulate Activity life cycle
- if (oldView != null) {
- oldView.onPause();
- }
-
- KeyguardInputViewController<KeyguardInputView> newView = changeSecurityMode(securityMode);
- if (newView != null) {
- newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
- mSecurityViewFlipperController.show(newView);
- }
-
- mSecurityCallback.onSecurityModeChanged(
- securityMode, newView != null && newView.needsInput());
- }
-
- public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
- // +1 for this time
- final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
-
- if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
-
- final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
- final int failedAttemptsBeforeWipe =
- dpm.getMaximumFailedPasswordsForWipe(null, userId);
-
- final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0
- ? (failedAttemptsBeforeWipe - failedAttempts)
- : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
- if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
- // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
- // N attempts. Once we get below the grace period, we post this dialog every time as a
- // clear warning until the deletion fires.
- // Check which profile has the strictest policy for failed password attempts
- final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(userId);
- int userType = USER_TYPE_PRIMARY;
- if (expiringUser == userId) {
- // TODO: http://b/23522538
- if (expiringUser != UserHandle.USER_SYSTEM) {
- userType = USER_TYPE_SECONDARY_USER;
- }
- } else if (expiringUser != UserHandle.USER_NULL) {
- userType = USER_TYPE_WORK_PROFILE;
- } // If USER_NULL, which shouldn't happen, leave it as USER_TYPE_PRIMARY
- if (remainingBeforeWipe > 0) {
- mView.showAlmostAtWipeDialog(failedAttempts, remainingBeforeWipe, userType);
- } else {
- // Too many attempts. The device will be wiped shortly.
- Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
- mView.showWipeDialog(failedAttempts, userType);
- }
- }
- mLockPatternUtils.reportFailedPasswordAttempt(userId);
- if (timeoutMs > 0) {
- mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
- mView.showTimeoutDialog(userId, timeoutMs, mLockPatternUtils,
- mSecurityModel.getSecurityMode(userId));
- }
+ return mView.needsInput();
}
- private KeyguardInputViewController<KeyguardInputView> getCurrentSecurityController() {
- return mSecurityViewFlipperController
- .getSecurityView(mCurrentSecurityMode, mKeyguardSecurityCallback);
- }
-
- private KeyguardInputViewController<KeyguardInputView> changeSecurityMode(
- SecurityMode securityMode) {
- mCurrentSecurityMode = securityMode;
- return getCurrentSecurityController();
+ public SecurityMode getCurrentSecurityMode() {
+ return mView.getCurrentSecurityMode();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index c77c86711abf..ac2160ecb4ae 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -18,14 +18,13 @@ package com.android.keyguard;
import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.app.admin.DevicePolicyManager;
-import android.content.res.Resources;
+import android.content.Context;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.Dependency;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
@@ -34,7 +33,7 @@ public class KeyguardSecurityModel {
/**
* The different types of security available.
- * @see KeyguardSecurityContainerController#showSecurityScreen
+ * @see KeyguardSecurityContainer#showSecurityScreen
*/
public enum SecurityMode {
Invalid, // NULL state
@@ -46,15 +45,21 @@ public class KeyguardSecurityModel {
SimPuk // Unlock by entering a sim puk
}
+ private final Context mContext;
private final boolean mIsPukScreenAvailable;
- private final LockPatternUtils mLockPatternUtils;
+ private LockPatternUtils mLockPatternUtils;
@Inject
- KeyguardSecurityModel(@Main Resources resources, LockPatternUtils lockPatternUtils) {
- mIsPukScreenAvailable = resources.getBoolean(
+ KeyguardSecurityModel(Context context) {
+ mContext = context;
+ mLockPatternUtils = new LockPatternUtils(context);
+ mIsPukScreenAvailable = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_enable_puk_unlock_screen);
- mLockPatternUtils = lockPatternUtils;
+ }
+
+ void setLockPatternUtils(LockPatternUtils utils) {
+ mLockPatternUtils = utils;
}
public SecurityMode getSecurityMode(int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index ac00e9453c97..43cef3acf147 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -18,9 +18,11 @@ package com.android.keyguard;
import android.content.res.ColorStateList;
import android.view.MotionEvent;
+import com.android.internal.widget.LockPatternUtils;
+
public interface KeyguardSecurityView {
- int SCREEN_ON = 1;
- int VIEW_REVEALED = 2;
+ static public final int SCREEN_ON = 1;
+ static public final int VIEW_REVEALED = 2;
int PROMPT_REASON_NONE = 0;
@@ -61,6 +63,18 @@ public interface KeyguardSecurityView {
int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
/**
+ * Interface back to keyguard to tell it when security
+ * @param callback
+ */
+ void setKeyguardCallback(KeyguardSecurityCallback callback);
+
+ /**
+ * Set {@link LockPatternUtils} object. Useful for providing a mock interface.
+ * @param utils
+ */
+ void setLockPatternUtils(LockPatternUtils utils);
+
+ /**
* Reset the view and prepare to take input. This should do things like clearing the
* password or pattern and clear error messages.
*/
@@ -87,6 +101,12 @@ public interface KeyguardSecurityView {
boolean needsInput();
/**
+ * Get {@link KeyguardSecurityCallback} for the given object
+ * @return KeyguardSecurityCallback
+ */
+ KeyguardSecurityCallback getCallback();
+
+ /**
* Show a string explaining why the security view needs to be solved.
*
* @param reason a flag indicating which string should be shown, see {@link #PROMPT_REASON_NONE}
@@ -103,6 +123,12 @@ public interface KeyguardSecurityView {
void showMessage(CharSequence message, ColorStateList colorState);
/**
+ * Instruct the view to show usability hints, if any.
+ *
+ */
+ void showUsabilityHint();
+
+ /**
* Starts the animation which should run when the security view appears.
*/
void startAppearAnimation();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
new file mode 100644
index 000000000000..ef9ba19fbb43
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard;
+
+import android.view.View;
+
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+
+
+/** Controller for a {@link KeyguardSecurityView}. */
+public class KeyguardSecurityViewController extends ViewController<View> {
+
+ private final KeyguardSecurityView mView;
+
+ private KeyguardSecurityViewController(KeyguardSecurityView view) {
+ super((View) view);
+ // KeyguardSecurityView isn't actually a View, so we need to track it ourselves.
+ mView = view;
+ }
+
+ @Override
+ protected void onViewAttached() {
+
+ }
+
+ @Override
+ protected void onViewDetached() {
+
+ }
+
+ /** Factory for a {@link KeyguardSecurityViewController}. */
+ public static class Factory {
+ @Inject
+ public Factory() {
+ }
+
+ /** Create a new {@link KeyguardSecurityViewController}. */
+ public KeyguardSecurityViewController create(KeyguardSecurityView view) {
+ return new KeyguardSecurityViewController(view);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
index b8439af6daaa..24da3ad46f23 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipper.java
@@ -18,6 +18,7 @@ package com.android.keyguard;
import android.annotation.NonNull;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -30,6 +31,7 @@ import android.view.ViewHierarchyEncoder;
import android.widget.FrameLayout;
import android.widget.ViewFlipper;
+import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
/**
@@ -37,7 +39,7 @@ import com.android.systemui.R;
* we can emulate {@link android.view.WindowManager.LayoutParams#FLAG_SLIPPERY} within a view
* hierarchy.
*/
-public class KeyguardSecurityViewFlipper extends ViewFlipper {
+public class KeyguardSecurityViewFlipper extends ViewFlipper implements KeyguardSecurityView {
private static final String TAG = "KeyguardSecurityViewFlipper";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -67,16 +69,111 @@ public class KeyguardSecurityViewFlipper extends ViewFlipper {
return result;
}
- KeyguardInputView getSecurityView() {
+ KeyguardSecurityView getSecurityView() {
View child = getChildAt(getDisplayedChild());
- if (child instanceof KeyguardInputView) {
- return (KeyguardInputView) child;
+ if (child instanceof KeyguardSecurityView) {
+ return (KeyguardSecurityView) child;
}
return null;
}
+ @Override
+ public void setKeyguardCallback(KeyguardSecurityCallback callback) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.setKeyguardCallback(callback);
+ }
+ }
+
+ @Override
+ public void setLockPatternUtils(LockPatternUtils utils) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.setLockPatternUtils(utils);
+ }
+ }
+
+ @Override
+ public void reset() {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.reset();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.onPause();
+ }
+ }
+
+ @Override
+ public void onResume(int reason) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.onResume(reason);
+ }
+ }
+
+ @Override
+ public boolean needsInput() {
+ KeyguardSecurityView ksv = getSecurityView();
+ return (ksv != null) ? ksv.needsInput() : false;
+ }
+
+ @Override
+ public KeyguardSecurityCallback getCallback() {
+ KeyguardSecurityView ksv = getSecurityView();
+ return (ksv != null) ? ksv.getCallback() : null;
+ }
+
+ @Override
+ public void showPromptReason(int reason) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.showPromptReason(reason);
+ }
+ }
+
+ @Override
+ public void showMessage(CharSequence message, ColorStateList colorState) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.showMessage(message, colorState);
+ }
+ }
+
+ @Override
+ public void showUsabilityHint() {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.showUsabilityHint();
+ }
+ }
+
+ @Override
+ public void startAppearAnimation() {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ ksv.startAppearAnimation();
+ }
+ }
+
+ @Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ KeyguardSecurityView ksv = getSecurityView();
+ if (ksv != null) {
+ return ksv.startDisappearAnimation(finishRunnable);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
public CharSequence getTitle() {
- KeyguardInputView ksv = getSecurityView();
+ KeyguardSecurityView ksv = getSecurityView();
if (ksv != null) {
return ksv.getTitle();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
deleted file mode 100644
index 49530355a6fb..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.util.Log;
-import android.view.LayoutInflater;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.KeyguardInputViewController.Factory;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.keyguard.dagger.KeyguardBouncerScope;
-import com.android.systemui.R;
-import com.android.systemui.util.ViewController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.inject.Inject;
-
-/**
- * Controller for a {@link KeyguardSecurityViewFlipper}.
- */
-@KeyguardBouncerScope
-public class KeyguardSecurityViewFlipperController
- extends ViewController<KeyguardSecurityViewFlipper> {
-
- private static final boolean DEBUG = KeyguardConstants.DEBUG;
- private static final String TAG = "KeyguardSecurityView";
-
- private final List<KeyguardInputViewController<KeyguardInputView>> mChildren =
- new ArrayList<>();
- private final LayoutInflater mLayoutInflater;
- private final Factory mKeyguardSecurityViewControllerFactory;
-
- @Inject
- protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view,
- LayoutInflater layoutInflater,
- KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory) {
- super(view);
- mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory;
- mLayoutInflater = layoutInflater;
- }
-
- @Override
- protected void onViewAttached() {
-
- }
-
- @Override
- protected void onViewDetached() {
-
- }
-
- public void reset() {
- for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
- child.reset();
- }
- }
-
- @VisibleForTesting
- KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode,
- KeyguardSecurityCallback keyguardSecurityCallback) {
- KeyguardInputViewController<KeyguardInputView> childController = null;
- for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
- if (child.getSecurityMode() == securityMode) {
- childController = child;
- break;
- }
- }
-
- if (childController == null
- && securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) {
-
- int layoutId = getLayoutIdFor(securityMode);
- KeyguardInputView view = null;
- if (layoutId != 0) {
- if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
- view = (KeyguardInputView) mLayoutInflater.inflate(
- layoutId, mView, false);
- mView.addView(view);
- childController = mKeyguardSecurityViewControllerFactory.create(
- view, securityMode, keyguardSecurityCallback);
- childController.init();
-
- mChildren.add(childController);
- }
- }
-
- if (childController == null) {
- childController = new NullKeyguardInputViewController(
- securityMode, keyguardSecurityCallback);
- }
-
- return childController;
- }
-
- private int getLayoutIdFor(SecurityMode securityMode) {
- switch (securityMode) {
- case Pattern: return com.android.systemui.R.layout.keyguard_pattern_view;
- case PIN: return com.android.systemui.R.layout.keyguard_pin_view;
- case Password: return com.android.systemui.R.layout.keyguard_password_view;
- case SimPin: return com.android.systemui.R.layout.keyguard_sim_pin_view;
- case SimPuk: return R.layout.keyguard_sim_puk_view;
- default:
- return 0;
- }
- }
-
- /** Makes the supplied child visible if it is contained win this view, */
- public void show(KeyguardInputViewController<KeyguardInputView> childController) {
- int index = childController.getIndexIn(mView);
- if (index != -1) {
- mView.setDisplayedChild(index);
- }
- }
-
- private static class NullKeyguardInputViewController
- extends KeyguardInputViewController<KeyguardInputView> {
- protected NullKeyguardInputViewController(SecurityMode securityMode,
- KeyguardSecurityCallback keyguardSecurityCallback) {
- super(null, securityMode, keyguardSecurityCallback);
- }
-
- @Override
- public boolean needsInput() {
- return false;
- }
-
- @Override
- public void onStartingToHide() {
-
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index c0f9ce794628..1c47aa0151f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -16,19 +16,66 @@
package com.android.keyguard;
+import android.annotation.NonNull;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.ProgressDialog;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.telephony.PinResult;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
/**
* Displays a PIN pad for unlocking.
*/
public class KeyguardSimPinView extends KeyguardPinBasedInputView {
+ private static final String LOG_TAG = "KeyguardSimPinView";
+ private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
public static final String TAG = "KeyguardSimPinView";
+ private ProgressDialog mSimUnlockProgressDialog = null;
+ private CheckSimPin mCheckSimPinThread;
+
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PIN attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
+ private AlertDialog mRemainingAttemptsDialog;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private ImageView mSimImageView;
+
+ KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSimStateChanged(int subId, int slotId, int simState) {
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ switch(simState) {
+ case TelephonyManager.SIM_STATE_READY: {
+ mRemainingAttempts = -1;
+ resetState();
+ break;
+ }
+ default:
+ resetState();
+ }
+ }
+ };
+
public KeyguardSimPinView(Context context) {
this(context, null);
}
@@ -37,9 +84,81 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
super(context, attrs);
}
- public void setEsimLocked(boolean locked) {
+ @Override
+ public void resetState() {
+ super.resetState();
+ if (DEBUG) Log.v(TAG, "Resetting state");
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
+ }
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
- esimButton.setVisibility(locked ? View.VISIBLE : View.GONE);
+ esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
+ }
+
+ private void setLockedSimMessage() {
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = 1;
+ TelephonyManager telephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ if (telephonyManager != null) {
+ count = telephonyManager.getActiveModemCount();
+ }
+ Resources rez = getResources();
+ String msg;
+ TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
+ int color = array.getColor(0, Color.WHITE);
+ array.recycle();
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
+ .getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
+ }
+
+ if (mSecurityMessageDisplay != null && getVisibility() == VISIBLE) {
+ mSecurityMessageDisplay.setMessage(msg);
+ }
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ }
+
+ private void showDefaultMessage() {
+ setLockedSimMessage();
+ if (mRemainingAttempts >= 0) {
+ return;
+ }
+
+ // Sending empty PIN here to query the number of remaining PIN attempts
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final PinResult result) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ + result.toString());
+ if (result.getAttemptsRemaining() >= 0) {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ setLockedSimMessage();
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
+ int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
}
@Override
@@ -54,6 +173,35 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
return 0;
}
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
+ String displayMessage;
+ int msgId;
+ if (attemptsRemaining == 0) {
+ displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
+ } else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
+ displayMessage = getContext().getResources()
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
+ } else {
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = getContext().getString(msgId);
+ }
+ if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) {
+ displayMessage = getResources()
+ .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
+ }
+ if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
+ return displayMessage;
+ }
+
+ @Override
+ protected boolean shouldLockout(long deadline) {
+ // SIM PIN doesn't have a timed lockout
+ return false;
+ }
+
@Override
protected int getPasswordTextViewId() {
return R.id.simPinEntry;
@@ -66,6 +214,173 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
if (mEcaView instanceof EmergencyCarrierArea) {
((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
}
+ mSimImageView = findViewById(R.id.keyguard_sim);
+ }
+
+ @Override
+ public void showUsabilityHint() {
+
+ }
+
+ @Override
+ public void onResume(int reason) {
+ super.onResume(reason);
+ Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback);
+ resetState();
+ }
+
+ @Override
+ public void onPause() {
+ // dismiss the dialog.
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.dismiss();
+ mSimUnlockProgressDialog = null;
+ }
+ Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback);
+ }
+
+ /**
+ * Since the IPC can block, we want to run the request in a separate thread
+ * with a callback.
+ */
+ private abstract class CheckSimPin extends Thread {
+ private final String mPin;
+ private int mSubId;
+
+ protected CheckSimPin(String pin, int subId) {
+ mPin = pin;
+ mSubId = subId;
+ }
+
+ abstract void onSimCheckResponse(@NonNull PinResult result);
+
+ @Override
+ public void run() {
+ if (DEBUG) {
+ Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
+ }
+ TelephonyManager telephonyManager =
+ ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .createForSubscriptionId(mSubId);
+ final PinResult result = telephonyManager.supplyPinReportPinResult(mPin);
+ if (result == null) {
+ Log.e(TAG, "Error result for supplyPinReportResult.");
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimCheckResponse(PinResult.getDefaultFailedResult());
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "supplyPinReportResult returned: " + result.toString());
+ }
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimCheckResponse(result);
+ }
+ });
+ }
+ }
+ }
+
+ private Dialog getSimUnlockProgressDialog() {
+ if (mSimUnlockProgressDialog == null) {
+ mSimUnlockProgressDialog = new ProgressDialog(mContext);
+ mSimUnlockProgressDialog.setMessage(
+ mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
+ mSimUnlockProgressDialog.setIndeterminate(true);
+ mSimUnlockProgressDialog.setCancelable(false);
+ mSimUnlockProgressDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ }
+ return mSimUnlockProgressDialog;
+ }
+
+ private Dialog getSimRemainingAttemptsDialog(int remaining) {
+ String msg = getPinPasswordErrorMessage(remaining, false);
+ if (mRemainingAttemptsDialog == null) {
+ Builder builder = new AlertDialog.Builder(mContext);
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
+ @Override
+ protected void verifyPasswordAndUnlock() {
+ String entry = mPasswordEntry.getText();
+
+ if (entry.length() < 4) {
+ // otherwise, display a message to the user, and don't submit.
+ mSecurityMessageDisplay.setMessage(R.string.kg_invalid_sim_pin_hint);
+ resetPasswordText(true /* animate */, true /* announce */);
+ mCallback.userActivity();
+ return;
+ }
+
+ getSimUnlockProgressDialog().show();
+
+ if (mCheckSimPinThread == null) {
+ mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) {
+ @Override
+ void onSimCheckResponse(final PinResult result) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.hide();
+ }
+ resetPasswordText(true /* animate */,
+ /* announce */
+ result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ Dependency.get(KeyguardUpdateMonitor.class)
+ .reportSimUnlocked(mSubId);
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
+ } else {
+ mShowDefaultMessage = false;
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ if (result.getAttemptsRemaining() <= 2) {
+ // this is getting critical - show dialog
+ getSimRemainingAttemptsDialog(
+ result.getAttemptsRemaining()).show();
+ } else {
+ // show message
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(
+ result.getAttemptsRemaining(), false));
+ }
+ } else {
+ // "PIN operation failed!" - no idea what this was and no way to
+ // find out. :/
+ mSecurityMessageDisplay.setMessage(getContext().getString(
+ R.string.kg_password_pin_failed));
+ }
+ if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " CheckSimPin.onSimCheckResponse: " + result
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
+ }
+ mCallback.userActivity();
+ mCheckSimPinThread = null;
+ }
+ });
+ }
+ };
+ mCheckSimPinThread.start();
+ }
}
@Override
@@ -74,6 +389,11 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
}
@Override
+ public boolean startDisappearAnimation(Runnable finishRunnable) {
+ return false;
+ }
+
+ @Override
public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
deleted file mode 100644
index cc8bf4f2d028..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.annotation.NonNull;
-import android.app.AlertDialog;
-import android.app.AlertDialog.Builder;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.telephony.PinResult;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.ImageView;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-
-public class KeyguardSimPinViewController
- extends KeyguardPinBasedInputViewController<KeyguardSimPinView> {
- public static final String TAG = "KeyguardSimPinView";
- private static final String LOG_TAG = "KeyguardSimPinView";
- private static final boolean DEBUG = KeyguardConstants.DEBUG_SIM_STATES;
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TelephonyManager mTelephonyManager;
-
- private ProgressDialog mSimUnlockProgressDialog;
- private CheckSimPin mCheckSimPinThread;
- private int mRemainingAttempts;
- // Below flag is set to true during power-up or when a new SIM card inserted on device.
- // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
- // be displayed to inform user about the number of remaining PIN attempts left.
- private boolean mShowDefaultMessage;
- private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private AlertDialog mRemainingAttemptsDialog;
- private ImageView mSimImageView;
-
- KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- if (simState == TelephonyManager.SIM_STATE_READY) {
- mRemainingAttempts = -1;
- resetState();
- } else {
- resetState();
- }
- }
- };
-
- protected KeyguardSimPinViewController(KeyguardSimPinView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode, LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
- super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTelephonyManager = telephonyManager;
- mSimImageView = mView.findViewById(R.id.keyguard_sim);
- }
-
- @Override
- protected void onViewAttached() {
- super.onViewAttached();
- }
-
- @Override
- void resetState() {
- super.resetState();
- if (DEBUG) Log.v(TAG, "Resetting state");
- handleSubInfoChangeIfNeeded();
- mMessageAreaController.setMessage("");
- if (mShowDefaultMessage) {
- showDefaultMessage();
- }
-
- mView.setEsimLocked(KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId));
- }
-
- @Override
- public boolean startDisappearAnimation(Runnable finishRunnable) {
- return false;
- }
-
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
- mView.resetState();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
-
- // dismiss the dialog.
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.dismiss();
- mSimUnlockProgressDialog = null;
- }
- }
-
- @Override
- protected void verifyPasswordAndUnlock() {
- String entry = mPasswordEntry.getText();
-
- if (entry.length() < 4) {
- // otherwise, display a message to the user, and don't submit.
- mMessageAreaController.setMessage(
- com.android.systemui.R.string.kg_invalid_sim_pin_hint);
- mView.resetPasswordText(true /* animate */, true /* announce */);
- getKeyguardSecurityCallback().userActivity();
- return;
- }
-
- getSimUnlockProgressDialog().show();
-
- if (mCheckSimPinThread == null) {
- mCheckSimPinThread = new CheckSimPin(mPasswordEntry.getText(), mSubId) {
- @Override
- void onSimCheckResponse(final PinResult result) {
- mView.post(() -> {
- mRemainingAttempts = result.getAttemptsRemaining();
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- mView.resetPasswordText(true /* animate */,
- /* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
- mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
- getKeyguardSecurityCallback().dismiss(
- true, KeyguardUpdateMonitor.getCurrentUser());
- } else {
- mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
- if (result.getAttemptsRemaining() <= 2) {
- // this is getting critical - show dialog
- getSimRemainingAttemptsDialog(
- result.getAttemptsRemaining()).show();
- } else {
- // show message
- mMessageAreaController.setMessage(
- getPinPasswordErrorMessage(
- result.getAttemptsRemaining(), false));
- }
- } else {
- // "PIN operation failed!" - no idea what this was and no way to
- // find out. :/
- mMessageAreaController.setMessage(mView.getResources().getString(
- R.string.kg_password_pin_failed));
- }
- if (DEBUG) {
- Log.d(LOG_TAG, "verifyPasswordAndUnlock "
- + " CheckSimPin.onSimCheckResponse: " + result
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
- }
- getKeyguardSecurityCallback().userActivity();
- mCheckSimPinThread = null;
- });
- }
- };
- mCheckSimPinThread.start();
- }
- }
-
- private Dialog getSimUnlockProgressDialog() {
- if (mSimUnlockProgressDialog == null) {
- mSimUnlockProgressDialog = new ProgressDialog(mView.getContext());
- mSimUnlockProgressDialog.setMessage(
- mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message));
- mSimUnlockProgressDialog.setIndeterminate(true);
- mSimUnlockProgressDialog.setCancelable(false);
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- }
- return mSimUnlockProgressDialog;
- }
-
-
- private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining, false);
- if (mRemainingAttemptsDialog == null) {
- Builder builder = new AlertDialog.Builder(mView.getContext());
- builder.setMessage(msg);
- builder.setCancelable(false);
- builder.setNeutralButton(R.string.ok, null);
- mRemainingAttemptsDialog = builder.create();
- mRemainingAttemptsDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mRemainingAttemptsDialog.setMessage(msg);
- }
- return mRemainingAttemptsDialog;
- }
-
-
- private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
- String displayMessage;
- int msgId;
- if (attemptsRemaining == 0) {
- displayMessage = mView.getResources().getString(
- R.string.kg_password_wrong_pin_code_pukked);
- } else if (attemptsRemaining > 0) {
- msgId = isDefault ? R.plurals.kg_password_default_pin_message :
- R.plurals.kg_password_wrong_pin_code;
- displayMessage = mView.getResources()
- .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
- } else {
- msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
- displayMessage = mView.getResources().getString(msgId);
- }
- if (KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)) {
- displayMessage = mView.getResources()
- .getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
- }
- if (DEBUG) {
- Log.d(LOG_TAG, "getPinPasswordErrorMessage: attemptsRemaining="
- + attemptsRemaining + " displayMessage=" + displayMessage);
- }
- return displayMessage;
- }
-
- private void showDefaultMessage() {
- setLockedSimMessage();
- if (mRemainingAttempts >= 0) {
- return;
- }
-
- // Sending empty PIN here to query the number of remaining PIN attempts
- new CheckSimPin("", mSubId) {
- void onSimCheckResponse(final PinResult result) {
- Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
- + result.toString());
- if (result.getAttemptsRemaining() >= 0) {
- mRemainingAttempts = result.getAttemptsRemaining();
- setLockedSimMessage();
- }
- }
- }.start();
- }
-
- /**
- * Since the IPC can block, we want to run the request in a separate thread
- * with a callback.
- */
- private abstract class CheckSimPin extends Thread {
- private final String mPin;
- private int mSubId;
-
- protected CheckSimPin(String pin, int subId) {
- mPin = pin;
- mSubId = subId;
- }
-
- abstract void onSimCheckResponse(@NonNull PinResult result);
-
- @Override
- public void run() {
- if (DEBUG) {
- Log.v(TAG, "call supplyPinReportResultForSubscriber(subid=" + mSubId + ")");
- }
- TelephonyManager telephonyManager =
- mTelephonyManager.createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPinReportPinResult(mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPinReportResult.");
- mView.post(() -> onSimCheckResponse(PinResult.getDefaultFailedResult()));
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPinReportResult returned: " + result.toString());
- }
- mView.post(() -> onSimCheckResponse(result));
- }
- }
- }
-
- private void setLockedSimMessage() {
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
- int count = 1;
- if (mTelephonyManager != null) {
- count = mTelephonyManager.getActiveModemCount();
- }
- Resources rez = mView.getResources();
- String msg;
- TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
- int color = array.getColor(0, Color.WHITE);
- array.recycle();
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = mKeyguardUpdateMonitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
- }
-
- if (mView.getVisibility() == View.VISIBLE) {
- mMessageAreaController.setMessage(msg);
- }
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
- }
-
- private void handleSubInfoChangeIfNeeded() {
- int subId = mKeyguardUpdateMonitor
- .getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
- if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
- mSubId = subId;
- mShowDefaultMessage = true;
- mRemainingAttempts = -1;
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 0d72c93e9041..5148dd709026 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -16,10 +16,27 @@
package com.android.keyguard;
+import android.annotation.NonNull;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.telephony.PinResult;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -27,9 +44,48 @@ import com.android.systemui.R;
* Displays a PIN pad for entering a PUK (Pin Unlock Kode) provided by a carrier.
*/
public class KeyguardSimPukView extends KeyguardPinBasedInputView {
+ private static final String LOG_TAG = "KeyguardSimPukView";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
public static final String TAG = "KeyguardSimPukView";
+ private ProgressDialog mSimUnlockProgressDialog = null;
+ private CheckSimPuk mCheckSimPukThread;
+
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PUK attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
+ private String mPukText;
+ private String mPinText;
+ private StateMachine mStateMachine = new StateMachine();
+ private AlertDialog mRemainingAttemptsDialog;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private ImageView mSimImageView;
+
+ KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onSimStateChanged(int subId, int slotId, int simState) {
+ if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
+ switch(simState) {
+ // If the SIM is unlocked via a key sequence through the emergency dialer, it will
+ // move into the READY state and the PUK lock keyguard should be removed.
+ case TelephonyManager.SIM_STATE_READY: {
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ // mCallback can be null if onSimStateChanged callback is called when keyguard
+ // isn't active.
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
+ break;
+ }
+ default:
+ resetState();
+ }
+ }
+ };
+
public KeyguardSimPukView(Context context) {
this(context, null);
}
@@ -38,14 +94,136 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
super(context, attrs);
}
+ private class StateMachine {
+ final int ENTER_PUK = 0;
+ final int ENTER_PIN = 1;
+ final int CONFIRM_PIN = 2;
+ final int DONE = 3;
+ private int state = ENTER_PUK;
+
+ public void next() {
+ int msg = 0;
+ if (state == ENTER_PUK) {
+ if (checkPuk()) {
+ state = ENTER_PIN;
+ msg = R.string.kg_puk_enter_pin_hint;
+ } else {
+ msg = R.string.kg_invalid_sim_puk_hint;
+ }
+ } else if (state == ENTER_PIN) {
+ if (checkPin()) {
+ state = CONFIRM_PIN;
+ msg = R.string.kg_enter_confirm_pin_hint;
+ } else {
+ msg = R.string.kg_invalid_sim_pin_hint;
+ }
+ } else if (state == CONFIRM_PIN) {
+ if (confirmPin()) {
+ state = DONE;
+ msg = R.string.keyguard_sim_unlock_progress_dialog_message;
+ updateSim();
+ } else {
+ state = ENTER_PIN; // try again?
+ msg = R.string.kg_invalid_confirm_pin_hint;
+ }
+ }
+ resetPasswordText(true /* animate */, true /* announce */);
+ if (msg != 0) {
+ mSecurityMessageDisplay.setMessage(msg);
+ }
+ }
+
+
+ void reset() {
+ mPinText="";
+ mPukText="";
+ state = ENTER_PUK;
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
+ }
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
+ KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
+ esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
+ mPasswordEntry.requestFocus();
+ }
+
+
+ }
+
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = 1;
+ TelephonyManager telephonyManager =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ if (telephonyManager != null) {
+ count = telephonyManager.getActiveModemCount();
+ }
+ Resources rez = getResources();
+ String msg;
+ TypedArray array = mContext.obtainStyledAttributes(new int[] { R.attr.wallpaperTextColor });
+ int color = array.getColor(0, Color.WHITE);
+ array.recycle();
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+ } else {
+ SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
+ .getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : "";
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
+ }
+ if (mSecurityMessageDisplay != null) {
+ mSecurityMessageDisplay.setMessage(msg);
+ }
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PUK here to query the number of remaining PIN attempts
+ new CheckSimPuk("", "", mSubId) {
+ void onSimLockChangedResponse(final PinResult result) {
+ if (result == null) Log.e(LOG_TAG, "onSimCheckResponse, pin result is NULL");
+ else {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ + result.toString());
+ if (result.getAttemptsRemaining() >= 0) {
+ mRemainingAttempts = result.getAttemptsRemaining();
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(result.getAttemptsRemaining(), true));
+ }
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
+ int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected int getPromptReasonStringRes(int reason) {
// No message on SIM Puk
return 0;
}
- String getPukPasswordErrorMessage(
- int attemptsRemaining, boolean isDefault, boolean isEsimLocked) {
+ private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
if (attemptsRemaining == 0) {
@@ -60,19 +238,28 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
R.string.kg_password_puk_failed;
displayMessage = getContext().getString(msgId);
}
- if (isEsimLocked) {
+ if (KeyguardEsimArea.isEsimLocked(mContext, mSubId)) {
displayMessage = getResources()
.getString(R.string.kg_sim_lock_esim_instructions, displayMessage);
}
- if (DEBUG) {
- Log.d(TAG, "getPukPasswordErrorMessage:"
- + " attemptsRemaining=" + attemptsRemaining
- + " displayMessage=" + displayMessage);
- }
+ if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+ + " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
return displayMessage;
}
@Override
+ public void resetState() {
+ super.resetState();
+ mStateMachine.reset();
+ }
+
+ @Override
+ protected boolean shouldLockout(long deadline) {
+ // SIM PUK doesn't have a timed lockout
+ return false;
+ }
+
+ @Override
protected int getPasswordTextViewId() {
return R.id.pukEntry;
}
@@ -84,6 +271,197 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
if (mEcaView instanceof EmergencyCarrierArea) {
((EmergencyCarrierArea) mEcaView).setCarrierTextVisible(true);
}
+ mSimImageView = findViewById(R.id.keyguard_sim);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mUpdateMonitorCallback);
+ resetState();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mUpdateMonitorCallback);
+ }
+
+ @Override
+ public void showUsabilityHint() {
+ }
+
+ @Override
+ public void onPause() {
+ // dismiss the dialog.
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.dismiss();
+ mSimUnlockProgressDialog = null;
+ }
+ }
+
+ /**
+ * Since the IPC can block, we want to run the request in a separate thread
+ * with a callback.
+ */
+ private abstract class CheckSimPuk extends Thread {
+
+ private final String mPin, mPuk;
+ private final int mSubId;
+
+ protected CheckSimPuk(String puk, String pin, int subId) {
+ mPuk = puk;
+ mPin = pin;
+ mSubId = subId;
+ }
+
+ abstract void onSimLockChangedResponse(@NonNull PinResult result);
+
+ @Override
+ public void run() {
+ if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
+ TelephonyManager telephonyManager =
+ ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .createForSubscriptionId(mSubId);
+ final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin);
+ if (result == null) {
+ Log.e(TAG, "Error result for supplyPukReportResult.");
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimLockChangedResponse(PinResult.getDefaultFailedResult());
+ }
+ });
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "supplyPukReportResult returned: " + result.toString());
+ }
+ post(new Runnable() {
+ @Override
+ public void run() {
+ onSimLockChangedResponse(result);
+ }
+ });
+ }
+ }
+ }
+
+ private Dialog getSimUnlockProgressDialog() {
+ if (mSimUnlockProgressDialog == null) {
+ mSimUnlockProgressDialog = new ProgressDialog(mContext);
+ mSimUnlockProgressDialog.setMessage(
+ mContext.getString(R.string.kg_sim_unlock_progress_dialog_message));
+ mSimUnlockProgressDialog.setIndeterminate(true);
+ mSimUnlockProgressDialog.setCancelable(false);
+ if (!(mContext instanceof Activity)) {
+ mSimUnlockProgressDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ }
+ }
+ return mSimUnlockProgressDialog;
+ }
+
+ private Dialog getPukRemainingAttemptsDialog(int remaining) {
+ String msg = getPukPasswordErrorMessage(remaining, false);
+ if (mRemainingAttemptsDialog == null) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setMessage(msg);
+ builder.setCancelable(false);
+ builder.setNeutralButton(R.string.ok, null);
+ mRemainingAttemptsDialog = builder.create();
+ mRemainingAttemptsDialog.getWindow().setType(
+ WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ } else {
+ mRemainingAttemptsDialog.setMessage(msg);
+ }
+ return mRemainingAttemptsDialog;
+ }
+
+ private boolean checkPuk() {
+ // make sure the puk is at least 8 digits long.
+ if (mPasswordEntry.getText().length() == 8) {
+ mPukText = mPasswordEntry.getText();
+ return true;
+ }
+ return false;
+ }
+
+ private boolean checkPin() {
+ // make sure the PIN is between 4 and 8 digits
+ int length = mPasswordEntry.getText().length();
+ if (length >= 4 && length <= 8) {
+ mPinText = mPasswordEntry.getText();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean confirmPin() {
+ return mPinText.equals(mPasswordEntry.getText());
+ }
+
+ private void updateSim() {
+ getSimUnlockProgressDialog().show();
+
+ if (mCheckSimPukThread == null) {
+ mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) {
+ @Override
+ void onSimLockChangedResponse(final PinResult result) {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ if (mSimUnlockProgressDialog != null) {
+ mSimUnlockProgressDialog.hide();
+ }
+ resetPasswordText(true /* animate */,
+ /* announce */
+ result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
+ Dependency.get(KeyguardUpdateMonitor.class)
+ .reportSimUnlocked(mSubId);
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true,
+ KeyguardUpdateMonitor.getCurrentUser());
+ }
+ } else {
+ mShowDefaultMessage = false;
+ if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
+ // show message
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ result.getAttemptsRemaining(), false));
+ if (result.getAttemptsRemaining() <= 2) {
+ // this is getting critical - show dialog
+ getPukRemainingAttemptsDialog(
+ result.getAttemptsRemaining()).show();
+ } else {
+ // show message
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(
+ result.getAttemptsRemaining(), false));
+ }
+ } else {
+ mSecurityMessageDisplay.setMessage(getContext().getString(
+ R.string.kg_password_puk_failed));
+ }
+ if (DEBUG) Log.d(LOG_TAG, "verifyPasswordAndUnlock "
+ + " UpdateSim.onSimCheckResponse: "
+ + " attemptsRemaining=" + result.getAttemptsRemaining());
+ }
+ mStateMachine.reset();
+ mCheckSimPukThread = null;
+ }
+ });
+ }
+ };
+ mCheckSimPukThread.start();
+ }
+ }
+
+ @Override
+ protected void verifyPasswordAndUnlock() {
+ mStateMachine.next();
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
deleted file mode 100644
index a87374939ba6..000000000000
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import android.annotation.NonNull;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.telephony.PinResult;
-import android.telephony.SubscriptionInfo;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.ImageView;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-
-public class KeyguardSimPukViewController
- extends KeyguardPinBasedInputViewController<KeyguardSimPukView> {
- private static final boolean DEBUG = KeyguardConstants.DEBUG;
- public static final String TAG = "KeyguardSimPukView";
-
- private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- private final TelephonyManager mTelephonyManager;
-
- private String mPukText;
- private String mPinText;
- private int mRemainingAttempts;
- // Below flag is set to true during power-up or when a new SIM card inserted on device.
- // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
- // be displayed to inform user about the number of remaining PUK attempts left.
- private boolean mShowDefaultMessage;
- private StateMachine mStateMachine = new StateMachine();
- private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- private CheckSimPuk mCheckSimPukThread;
- private ProgressDialog mSimUnlockProgressDialog;
-
- KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
- @Override
- public void onSimStateChanged(int subId, int slotId, int simState) {
- if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
- // If the SIM is unlocked via a key sequence through the emergency dialer, it will
- // move into the READY state and the PUK lock keyguard should be removed.
- if (simState == TelephonyManager.SIM_STATE_READY) {
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
- getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
- } else {
- resetState();
- }
- }
- };
- private ImageView mSimImageView;
- private AlertDialog mRemainingAttemptsDialog;
-
- protected KeyguardSimPukViewController(KeyguardSimPukView view,
- KeyguardUpdateMonitor keyguardUpdateMonitor,
- SecurityMode securityMode, LockPatternUtils lockPatternUtils,
- KeyguardSecurityCallback keyguardSecurityCallback,
- KeyguardMessageAreaController.Factory messageAreaControllerFactory,
- LatencyTracker latencyTracker,
- LiftToActivateListener liftToActivateListener,
- TelephonyManager telephonyManager) {
- super(view, keyguardUpdateMonitor, securityMode, lockPatternUtils, keyguardSecurityCallback,
- messageAreaControllerFactory, latencyTracker, liftToActivateListener);
- mKeyguardUpdateMonitor = keyguardUpdateMonitor;
- mTelephonyManager = telephonyManager;
- mSimImageView = mView.findViewById(R.id.keyguard_sim);
- }
-
- @Override
- protected void onViewAttached() {
- super.onViewAttached();
- mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
- }
-
- @Override
- protected void onViewDetached() {
- super.onViewDetached();
- mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
- }
-
- @Override
- void resetState() {
- super.resetState();
- mStateMachine.reset();
- }
-
- @Override
- protected void verifyPasswordAndUnlock() {
- mStateMachine.next();
- }
-
- private class StateMachine {
- static final int ENTER_PUK = 0;
- static final int ENTER_PIN = 1;
- static final int CONFIRM_PIN = 2;
- static final int DONE = 3;
-
- private int mState = ENTER_PUK;
-
- public void next() {
- int msg = 0;
- if (mState == ENTER_PUK) {
- if (checkPuk()) {
- mState = ENTER_PIN;
- msg = com.android.systemui.R.string.kg_puk_enter_pin_hint;
- } else {
- msg = com.android.systemui.R.string.kg_invalid_sim_puk_hint;
- }
- } else if (mState == ENTER_PIN) {
- if (checkPin()) {
- mState = CONFIRM_PIN;
- msg = com.android.systemui.R.string.kg_enter_confirm_pin_hint;
- } else {
- msg = com.android.systemui.R.string.kg_invalid_sim_pin_hint;
- }
- } else if (mState == CONFIRM_PIN) {
- if (confirmPin()) {
- mState = DONE;
- msg = com.android.systemui.R.string.keyguard_sim_unlock_progress_dialog_message;
- updateSim();
- } else {
- mState = ENTER_PIN; // try again?
- msg = com.android.systemui.R.string.kg_invalid_confirm_pin_hint;
- }
- }
- mView.resetPasswordText(true /* animate */, true /* announce */);
- if (msg != 0) {
- mMessageAreaController.setMessage(msg);
- }
- }
-
-
- void reset() {
- mPinText = "";
- mPukText = "";
- mState = ENTER_PUK;
- handleSubInfoChangeIfNeeded();
- if (mShowDefaultMessage) {
- showDefaultMessage();
- }
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
-
- KeyguardEsimArea esimButton = mView.findViewById(R.id.keyguard_esim_area);
- esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
- mPasswordEntry.requestFocus();
- }
- }
-
- private void showDefaultMessage() {
- if (mRemainingAttempts >= 0) {
- mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage(
- mRemainingAttempts, true,
- KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
- return;
- }
-
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId);
- int count = 1;
- if (mTelephonyManager != null) {
- count = mTelephonyManager.getActiveModemCount();
- }
- Resources rez = mView.getResources();
- String msg;
- TypedArray array = mView.getContext().obtainStyledAttributes(
- new int[] { R.attr.wallpaperTextColor });
- int color = array.getColor(0, Color.WHITE);
- array.recycle();
- if (count < 2) {
- msg = rez.getString(R.string.kg_puk_enter_puk_hint);
- } else {
- SubscriptionInfo info = Dependency.get(KeyguardUpdateMonitor.class)
- .getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : "";
- msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = rez.getString(R.string.kg_sim_lock_esim_instructions, msg);
- }
- mMessageAreaController.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
-
- // Sending empty PUK here to query the number of remaining PIN attempts
- new CheckSimPuk("", "", mSubId) {
- void onSimLockChangedResponse(final PinResult result) {
- if (result == null) Log.e(TAG, "onSimCheckResponse, pin result is NULL");
- else {
- Log.d(TAG, "onSimCheckResponse " + " empty One result "
- + result.toString());
- if (result.getAttemptsRemaining() >= 0) {
- mRemainingAttempts = result.getAttemptsRemaining();
- mMessageAreaController.setMessage(
- mView.getPukPasswordErrorMessage(
- result.getAttemptsRemaining(), true,
- KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
- }
- }
- }
- }.start();
- }
-
- private boolean checkPuk() {
- // make sure the puk is at least 8 digits long.
- if (mPasswordEntry.getText().length() == 8) {
- mPukText = mPasswordEntry.getText();
- return true;
- }
- return false;
- }
-
- private boolean checkPin() {
- // make sure the PIN is between 4 and 8 digits
- int length = mPasswordEntry.getText().length();
- if (length >= 4 && length <= 8) {
- mPinText = mPasswordEntry.getText();
- return true;
- }
- return false;
- }
-
- public boolean confirmPin() {
- return mPinText.equals(mPasswordEntry.getText());
- }
-
-
-
-
- private void updateSim() {
- getSimUnlockProgressDialog().show();
-
- if (mCheckSimPukThread == null) {
- mCheckSimPukThread = new CheckSimPuk(mPukText, mPinText, mSubId) {
- @Override
- void onSimLockChangedResponse(final PinResult result) {
- mView.post(() -> {
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.hide();
- }
- mView.resetPasswordText(true /* animate */,
- /* announce */
- result.getType() != PinResult.PIN_RESULT_TYPE_SUCCESS);
- if (result.getType() == PinResult.PIN_RESULT_TYPE_SUCCESS) {
- mKeyguardUpdateMonitor.reportSimUnlocked(mSubId);
- mRemainingAttempts = -1;
- mShowDefaultMessage = true;
-
- getKeyguardSecurityCallback().dismiss(
- true, KeyguardUpdateMonitor.getCurrentUser());
- } else {
- mShowDefaultMessage = false;
- if (result.getType() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
- // show message
- mMessageAreaController.setMessage(mView.getPukPasswordErrorMessage(
- result.getAttemptsRemaining(), false,
- KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId)));
- if (result.getAttemptsRemaining() <= 2) {
- // this is getting critical - show dialog
- getPukRemainingAttemptsDialog(
- result.getAttemptsRemaining()).show();
- } else {
- // show message
- mMessageAreaController.setMessage(
- mView.getPukPasswordErrorMessage(
- result.getAttemptsRemaining(), false,
- KeyguardEsimArea.isEsimLocked(
- mView.getContext(), mSubId)));
- }
- } else {
- mMessageAreaController.setMessage(mView.getResources().getString(
- R.string.kg_password_puk_failed));
- }
- if (DEBUG) {
- Log.d(TAG, "verifyPasswordAndUnlock "
- + " UpdateSim.onSimCheckResponse: "
- + " attemptsRemaining=" + result.getAttemptsRemaining());
- }
- }
- mStateMachine.reset();
- mCheckSimPukThread = null;
- });
- }
- };
- mCheckSimPukThread.start();
- }
- }
-
- @Override
- protected boolean shouldLockout(long deadline) {
- // SIM PUK doesn't have a timed lockout
- return false;
- }
-
- private Dialog getSimUnlockProgressDialog() {
- if (mSimUnlockProgressDialog == null) {
- mSimUnlockProgressDialog = new ProgressDialog(mView.getContext());
- mSimUnlockProgressDialog.setMessage(
- mView.getResources().getString(R.string.kg_sim_unlock_progress_dialog_message));
- mSimUnlockProgressDialog.setIndeterminate(true);
- mSimUnlockProgressDialog.setCancelable(false);
- if (!(mView.getContext() instanceof Activity)) {
- mSimUnlockProgressDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- }
- }
- return mSimUnlockProgressDialog;
- }
-
- private void handleSubInfoChangeIfNeeded() {
- int subId = mKeyguardUpdateMonitor.getNextSubIdForState(
- TelephonyManager.SIM_STATE_PUK_REQUIRED);
- if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
- mSubId = subId;
- mShowDefaultMessage = true;
- mRemainingAttempts = -1;
- }
- }
-
-
- private Dialog getPukRemainingAttemptsDialog(int remaining) {
- String msg = mView.getPukPasswordErrorMessage(remaining, false,
- KeyguardEsimArea.isEsimLocked(mView.getContext(), mSubId));
- if (mRemainingAttemptsDialog == null) {
- AlertDialog.Builder builder = new AlertDialog.Builder(mView.getContext());
- builder.setMessage(msg);
- builder.setCancelable(false);
- builder.setNeutralButton(R.string.ok, null);
- mRemainingAttemptsDialog = builder.create();
- mRemainingAttemptsDialog.getWindow().setType(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- } else {
- mRemainingAttemptsDialog.setMessage(msg);
- }
- return mRemainingAttemptsDialog;
- }
-
- @Override
- public void onPause() {
- // dismiss the dialog.
- if (mSimUnlockProgressDialog != null) {
- mSimUnlockProgressDialog.dismiss();
- mSimUnlockProgressDialog = null;
- }
- }
-
- /**
- * Since the IPC can block, we want to run the request in a separate thread
- * with a callback.
- */
- private abstract class CheckSimPuk extends Thread {
-
- private final String mPin, mPuk;
- private final int mSubId;
-
- protected CheckSimPuk(String puk, String pin, int subId) {
- mPuk = puk;
- mPin = pin;
- mSubId = subId;
- }
-
- abstract void onSimLockChangedResponse(@NonNull PinResult result);
-
- @Override
- public void run() {
- if (DEBUG) Log.v(TAG, "call supplyPukReportResult()");
- TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
- final PinResult result = telephonyManager.supplyPukReportPinResult(mPuk, mPin);
- if (result == null) {
- Log.e(TAG, "Error result for supplyPukReportResult.");
- mView.post(() -> onSimLockChangedResponse(PinResult.getDefaultFailedResult()));
- } else {
- if (DEBUG) {
- Log.v(TAG, "supplyPukReportResult returned: " + result.toString());
- }
- mView.post(new Runnable() {
- @Override
- public void run() {
- onSimLockChangedResponse(result);
- }
- });
- }
- }
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
index 425e50ed6397..e59602b1cfff 100644
--- a/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
+++ b/packages/SystemUI/src/com/android/keyguard/LiftToActivateListener.java
@@ -16,12 +16,11 @@
package com.android.keyguard;
+import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import javax.inject.Inject;
-
/**
* Hover listener that implements lift-to-activate interaction for
* accessibility. May be added to multiple views.
@@ -32,9 +31,9 @@ class LiftToActivateListener implements View.OnHoverListener {
private boolean mCachedClickableState;
- @Inject
- LiftToActivateListener(AccessibilityManager accessibilityManager) {
- mAccessibilityManager = accessibilityManager;
+ public LiftToActivateListener(Context context) {
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 2205fdd4267d..b0457fce6a1a 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -26,7 +26,6 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
@@ -91,8 +90,7 @@ public class NumPadKey extends ViewGroup {
}
setOnClickListener(mListener);
- setOnHoverListener(new LiftToActivateListener(
- (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)));
+ setOnHoverListener(new LiftToActivateListener(context));
mLockPatternUtils = new LockPatternUtils(context);
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
index 881108858b51..b6010c8915e7 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java
@@ -22,7 +22,6 @@ import android.view.ViewGroup;
import com.android.keyguard.KeyguardHostView;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSecurityContainer;
-import com.android.keyguard.KeyguardSecurityViewFlipper;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
@@ -59,15 +58,7 @@ public interface KeyguardBouncerModule {
/** */
@Provides
@KeyguardBouncerScope
- static KeyguardSecurityContainer providesKeyguardSecurityContainer(KeyguardHostView hostView) {
+ static KeyguardSecurityContainer preovidesKeyguardSecurityContainer(KeyguardHostView hostView) {
return hostView.findViewById(R.id.keyguard_security_container);
}
-
- /** */
- @Provides
- @KeyguardBouncerScope
- static KeyguardSecurityViewFlipper providesKeyguardSecurityViewFlipper(
- KeyguardSecurityContainer containerView) {
- return containerView.findViewById(R.id.view_flipper);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 1b2e4c6a595e..02a672b587d8 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -26,6 +26,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ResolveInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
@@ -66,8 +68,10 @@ import dagger.Lazy;
@SysUISingleton
final class AssistHandleReminderExpBehavior implements BehaviorController {
- private static final String LEARNING_TIME_ELAPSED_KEY = "reminder_exp_learning_time_elapsed";
- private static final String LEARNING_EVENT_COUNT_KEY = "reminder_exp_learning_event_count";
+ private static final Uri LEARNING_TIME_ELAPSED_URI =
+ Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS);
+ private static final Uri LEARNING_EVENT_COUNT_URI =
+ Settings.Secure.getUriFor(Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT);
private static final String LEARNED_HINT_LAST_SHOWN_KEY =
"reminder_exp_learned_hint_last_shown";
private static final long DEFAULT_LEARNING_TIME_MS = TimeUnit.DAYS.toMillis(10);
@@ -181,6 +185,7 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
private boolean mIsNavBarHidden;
private boolean mIsLauncherShowing;
private int mConsecutiveTaskSwitches;
+ @Nullable private ContentObserver mSettingObserver;
/** Whether user has learned the gesture. */
private boolean mIsLearned;
@@ -248,9 +253,22 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
mWakefulnessLifecycle.get().addObserver(mWakefulnessLifecycleObserver);
mLearningTimeElapsed = Settings.Secure.getLong(
- context.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, /* default = */ 0);
+ context.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ /* default = */ 0);
mLearningCount = Settings.Secure.getInt(
- context.getContentResolver(), LEARNING_EVENT_COUNT_KEY, /* default = */ 0);
+ context.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+ /* default = */ 0);
+ mSettingObserver = new SettingsObserver(context, mHandler);
+ context.getContentResolver().registerContentObserver(
+ LEARNING_TIME_ELAPSED_URI,
+ /* notifyForDescendants = */ true,
+ mSettingObserver);
+ context.getContentResolver().registerContentObserver(
+ LEARNING_EVENT_COUNT_URI,
+ /* notifyForDescendants = */ true,
+ mSettingObserver);
mLearnedHintLastShownEpochDay = Settings.Secure.getLong(
context.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, /* default = */ 0);
mLastLearningTimestamp = mClock.currentTimeMillis();
@@ -264,8 +282,20 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
if (mContext != null) {
mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
mBootCompleteCache.get().removeListener(mBootCompleteListener);
- Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0);
- Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0);
+ mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+ mSettingObserver = null;
+ // putString in order to use overrideableByRestore
+ Settings.Secure.putString(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ Long.toString(0L),
+ /* overrideableByRestore = */ true);
+ // putString in order to use overrideableByRestore
+ Settings.Secure.putString(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+ Integer.toString(0),
+ /* overrideableByRestore = */ true);
Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
mContext = null;
}
@@ -282,8 +312,12 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
return;
}
- Settings.Secure.putLong(
- mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, ++mLearningCount);
+ // putString in order to use overrideableByRestore
+ Settings.Secure.putString(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+ Integer.toString(++mLearningCount),
+ /* overrideableByRestore = */ true);
}
@Override
@@ -460,8 +494,12 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
mIsLearned =
mLearningCount >= getLearningCount() || mLearningTimeElapsed >= getLearningTimeMs();
- mHandler.post(() -> Settings.Secure.putLong(
- mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, mLearningTimeElapsed));
+ // putString in order to use overrideableByRestore
+ mHandler.post(() -> Settings.Secure.putString(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ Long.toString(mLearningTimeElapsed),
+ /* overrideableByRestore = */ true));
}
private void resetConsecutiveTaskSwitches() {
@@ -589,4 +627,32 @@ final class AssistHandleReminderExpBehavior implements BehaviorController {
+ "="
+ getShowWhenTaught());
}
+
+ private final class SettingsObserver extends ContentObserver {
+
+ private final Context mContext;
+
+ SettingsObserver(Context context, Handler handler) {
+ super(handler);
+ mContext = context;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, @Nullable Uri uri) {
+ if (LEARNING_TIME_ELAPSED_URI.equals(uri)) {
+ mLastLearningTimestamp = mClock.currentTimeMillis();
+ mLearningTimeElapsed = Settings.Secure.getLong(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_TIME_ELAPSED_MILLIS,
+ /* default = */ 0);
+ } else if (LEARNING_EVENT_COUNT_URI.equals(uri)) {
+ mLearningCount = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ASSIST_HANDLES_LEARNING_EVENT_COUNT,
+ /* default = */ 0);
+ }
+
+ super.onChange(selfChange, uri);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index eb431274b8a3..38e12a6ed5f8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -288,7 +288,6 @@ public class DependencyProvider {
/** */
@Provides
- @SysUISingleton
public LockPatternUtils provideLockPatternUtils(Context context) {
return new LockPatternUtils(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 79925bad3cc7..b35579d3624b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -62,7 +62,6 @@ import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
-import android.view.inputmethod.InputMethodManager;
import com.android.internal.app.IBatteryStats;
import com.android.internal.statusbar.IStatusBarService;
@@ -184,12 +183,6 @@ public class FrameworkServicesModule {
@Provides
@Singleton
- static InputMethodManager provideInputMethodManager(Context context) {
- return context.getSystemService(InputMethodManager.class);
- }
-
- @Provides
- @Singleton
static IPackageManager provideIPackageManager() {
return IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index f150381f4070..636f42089743 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -274,7 +274,7 @@ class MediaCarouselController @Inject constructor(
}
}
- private fun removePlayer(key: String) {
+ private fun removePlayer(key: String, dismissMediaData: Boolean = true) {
val removed = MediaPlayerData.removeMediaPlayer(key)
removed?.apply {
mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
@@ -283,13 +283,16 @@ class MediaCarouselController @Inject constructor(
mediaCarouselScrollHandler.onPlayersChanged()
updatePageIndicator()
- // Inform the media manager of a potentially late dismissal
- mediaManager.dismissMediaData(key, 0L)
+ if (dismissMediaData) {
+ // Inform the media manager of a potentially late dismissal
+ mediaManager.dismissMediaData(key, 0L)
+ }
}
}
private fun recreatePlayers() {
MediaPlayerData.mediaData().forEach { (key, data) ->
+ removePlayer(key, dismissMediaData = false)
addOrUpdatePlayer(key = key, oldKey = null, data = data)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 9fc64d51cdf7..9b6a9ea80ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -42,7 +42,7 @@ import java.util.List;
public class MediaOutputAdapter extends MediaOutputBaseAdapter {
private static final String TAG = "MediaOutputAdapter";
- private static final int PAIR_NEW = 1;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public MediaOutputAdapter(MediaOutputController controller) {
super(controller);
@@ -58,11 +58,14 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override
public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
- if (mController.isZeroMode() && position == (mController.getMediaDevices().size())) {
- viewHolder.onBind(PAIR_NEW);
- } else if (position < (mController.getMediaDevices().size())) {
- viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position));
- } else {
+ final int size = mController.getMediaDevices().size();
+ if (mController.isZeroMode() && position == size) {
+ viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
+ true /* bottomMargin */);
+ } else if (position < size) {
+ viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
+ position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
+ } else if (DEBUG) {
Log.d(TAG, "Incorrect position: " + position);
}
}
@@ -83,7 +86,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
void onItemClick(int customizedItem) {
- if (customizedItem == PAIR_NEW) {
+ if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
mController.launchBluetoothPairing();
}
}
@@ -112,51 +115,49 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
- void onBind(MediaDevice device) {
- super.onBind(device);
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
+ super.onBind(device, topMargin, bottomMargin);
if (mController.isTransferring()) {
if (device.getState() == MediaDeviceState.STATE_CONNECTING
&& !mController.hasAdjustVolumeUserRestriction()) {
- setTwoLineLayout(device, true);
- mProgressBar.setVisibility(View.VISIBLE);
- mSeekBar.setVisibility(View.GONE);
- mSubTitleText.setVisibility(View.GONE);
+ setTwoLineLayout(device, null /* title */, true /* bFocused */,
+ false /* showSeekBar*/, true /* showProgressBar */,
+ false /* showSubtitle */);
} else {
- setSingleLineLayout(getItemTitle(device), false);
+ setSingleLineLayout(getItemTitle(device), false /* bFocused */);
}
} else {
// Set different layout for each device
if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
- setTwoLineLayout(device, false);
- mSubTitleText.setVisibility(View.VISIBLE);
- mSeekBar.setVisibility(View.GONE);
- mProgressBar.setVisibility(View.GONE);
+ setTwoLineLayout(device, null /* title */, false /* bFocused */,
+ false /* showSeekBar*/, false /* showProgressBar */,
+ true /* showSubtitle */);
mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
mFrameLayout.setOnClickListener(v -> onItemClick(device));
} else if (!mController.hasAdjustVolumeUserRestriction()
&& isCurrentConnected(device)) {
- setTwoLineLayout(device, true);
- mSeekBar.setVisibility(View.VISIBLE);
- mProgressBar.setVisibility(View.GONE);
- mSubTitleText.setVisibility(View.GONE);
+ setTwoLineLayout(device, null /* title */, true /* bFocused */,
+ true /* showSeekBar*/, false /* showProgressBar */,
+ false /* showSubtitle */);
initSeekbar(device);
} else {
- setSingleLineLayout(getItemTitle(device), false);
+ setSingleLineLayout(getItemTitle(device), false /* bFocused */);
mFrameLayout.setOnClickListener(v -> onItemClick(device));
}
}
}
@Override
- void onBind(int customizedItem) {
- if (customizedItem == PAIR_NEW) {
+ void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+ super.onBind(customizedItem, topMargin, bottomMargin);
+ if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
- false);
+ false /* bFocused */);
final Drawable d = mContext.getDrawable(R.drawable.ic_add);
d.setColorFilter(new PorterDuffColorFilter(
Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
mTitleIcon.setImageDrawable(d);
- mFrameLayout.setOnClickListener(v -> onItemClick(PAIR_NEW));
+ mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 7579c25b030a..01dc6c4b71da 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -44,9 +44,12 @@ public abstract class MediaOutputBaseAdapter extends
private static final String FONT_SELECTED_TITLE = "sans-serif-medium";
private static final String FONT_TITLE = "sans-serif";
+ static final int CUSTOMIZED_ITEM_PAIR_NEW = 1;
+
final MediaOutputController mController;
private boolean mIsDragging;
+ private int mMargin;
Context mContext;
View mHolderView;
@@ -60,6 +63,8 @@ public abstract class MediaOutputBaseAdapter extends
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
mContext = viewGroup.getContext();
+ mMargin = mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_list_margin);
mHolderView = LayoutInflater.from(mContext).inflate(R.layout.media_output_list_item,
viewGroup, false);
@@ -106,12 +111,26 @@ public abstract class MediaOutputBaseAdapter extends
mSeekBar = view.requireViewById(R.id.volume_seekbar);
}
- void onBind(MediaDevice device) {
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
mTitleIcon.setImageIcon(mController.getDeviceIconCompat(device).toIcon(mContext));
+ setMargin(topMargin, bottomMargin);
}
- void onBind(int customizedItem) { }
+ void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+ setMargin(topMargin, bottomMargin);
+ }
+ private void setMargin(boolean topMargin, boolean bottomMargin) {
+ ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout
+ .getLayoutParams();
+ if (topMargin) {
+ params.topMargin = mMargin;
+ }
+ if (bottomMargin) {
+ params.bottomMargin = mMargin;
+ }
+ mFrameLayout.setLayoutParams(params);
+ }
void setSingleLineLayout(CharSequence title, boolean bFocused) {
mTitleText.setVisibility(View.VISIBLE);
mTwoLineLayout.setVisibility(View.GONE);
@@ -123,10 +142,19 @@ public abstract class MediaOutputBaseAdapter extends
}
}
- void setTwoLineLayout(MediaDevice device, boolean bFocused) {
+ void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused,
+ boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {
mTitleText.setVisibility(View.GONE);
mTwoLineLayout.setVisibility(View.VISIBLE);
- mTwoLineTitleText.setText(getItemTitle(device));
+ mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
+ mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
+ mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+ if (device == null) {
+ mTwoLineTitleText.setText(title);
+ } else {
+ mTwoLineTitleText.setText(getItemTitle(device));
+ }
+
if (bFocused) {
mTwoLineTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE,
Typeface.NORMAL));
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index f8f4f4df58bc..ebca8a735ad5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -33,7 +33,6 @@ import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.Button;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -69,12 +68,9 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
private LinearLayout mDeviceListLayout;
private Button mDoneButton;
private Button mStopButton;
- private View mListBottomPadding;
private int mListMaxHeight;
MediaOutputBaseAdapter mAdapter;
- FrameLayout mGroupItemController;
- View mGroupDivider;
private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
// Set max height for list
@@ -114,12 +110,9 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
- mGroupItemController = mDialogView.requireViewById(R.id.group_item_controller);
- mGroupDivider = mDialogView.requireViewById(R.id.group_item_divider);
mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
mDoneButton = mDialogView.requireViewById(R.id.done);
mStopButton = mDialogView.requireViewById(R.id.stop);
- mListBottomPadding = mDialogView.requireViewById(R.id.list_bottom_padding);
mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
mDeviceListLayoutListener);
@@ -162,7 +155,9 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
}
if (mHeaderIcon.getVisibility() == View.VISIBLE) {
final int size = getHeaderIconSize();
- mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size, size));
+ final int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.media_output_dialog_header_icon_padding);
+ mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
}
// Update title and subtitle
mHeaderTitle.setText(getHeaderText());
@@ -178,12 +173,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
if (!mAdapter.isDragging()) {
mAdapter.notifyDataSetChanged();
}
- // Add extra padding when device amount is less than 6
- if (mMediaOutputController.getMediaDevices().size() < 6) {
- mListBottomPadding.setVisibility(View.VISIBLE);
- } else {
- mListBottomPadding.setVisibility(View.GONE);
- }
+ // Show when remote media session is available
+ mStopButton.setVisibility(getStopButtonVisibility());
}
abstract int getHeaderIconRes();
@@ -196,6 +187,8 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
abstract CharSequence getHeaderSubtitle();
+ abstract int getStopButtonVisibility();
+
@Override
public void onMediaChanged() {
mMainThreadHandler.post(() -> refresh());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 64d20a273931..b1f1bda25961 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -24,6 +24,7 @@ import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaMetadata;
+import android.media.MediaRoute2Info;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -63,7 +64,7 @@ import javax.inject.Inject;
public class MediaOutputController implements LocalMediaManager.DeviceCallback{
private static final String TAG = "MediaOutputController";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final String mPackageName;
private final Context mContext;
@@ -406,6 +407,14 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback{
mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true);
}
+ boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
+ final List<String> features = device.getFeatures();
+ return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
+ || features.contains(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK)
+ || features.contains(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK)
+ || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
+ }
+
private final MediaController.Callback mCb = new MediaController.Callback() {
@Override
public void onMetadataChanged(MediaMetadata metadata) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index ac9d8ce52d88..a892a12f387b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -45,8 +45,6 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mGroupItemController.setVisibility(View.GONE);
- mGroupDivider.setVisibility(View.GONE);
}
@Override
@@ -74,4 +72,10 @@ public class MediaOutputDialog extends MediaOutputBaseDialog {
CharSequence getHeaderSubtitle() {
return mMediaOutputController.getHeaderSubTitle();
}
+
+ @Override
+ int getStopButtonVisibility() {
+ return mMediaOutputController.isActiveRemoteDevice(
+ mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index bc1dca58990d..4cdca4cbcf1e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -33,10 +33,22 @@ class MediaOutputDialogFactory @Inject constructor(
private val shadeController: ShadeController,
private val starter: ActivityStarter
) {
+ companion object {
+ var mediaOutputDialog: MediaOutputDialog? = null
+ }
+
/** Creates a [MediaOutputDialog] for the given package. */
fun create(packageName: String, aboveStatusBar: Boolean) {
- MediaOutputController(context, packageName, mediaSessionManager, lbm, shadeController,
- starter).run {
+ mediaOutputDialog?.dismiss()
+
+ mediaOutputDialog = MediaOutputController(context, packageName, mediaSessionManager, lbm,
+ shadeController, starter).run {
MediaOutputDialog(context, aboveStatusBar, this) }
}
+
+ /** dismiss [MediaOutputDialog] if exist. */
+ fun dismiss() {
+ mediaOutputDialog?.dismiss()
+ mediaOutputDialog = null
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 5b07db6c91a1..a3913aa9db93 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -254,7 +254,9 @@ public class PipMenuActivityController {
if (isMenuVisible()) {
// If the menu is visible in either the closed or full state, then hide the menu and
// trigger the animation trigger afterwards
- onStartCallback.run();
+ if (onStartCallback != null) {
+ onStartCallback.run();
+ }
mPipMenuView.hideMenu(onEndCallback);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
index c66f442c4c0d..1c38ab338969 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuView.java
@@ -316,7 +316,7 @@ public class PipMenuView extends FrameLayout {
}
void hideMenu(Runnable animationEndCallback) {
- hideMenu(animationEndCallback, true /* notifyMenuVisibility */, false);
+ hideMenu(animationEndCallback, true /* notifyMenuVisibility */, true /* animate */);
}
private void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
@@ -394,8 +394,10 @@ public class PipMenuView extends FrameLayout {
// TODO: Check if the action drawable has changed before we reload it
action.getIcon().loadDrawableAsync(mContext, d -> {
- d.setTint(Color.WHITE);
- actionView.setImageDrawable(d);
+ if (d != null) {
+ d.setTint(Color.WHITE);
+ actionView.setImageDrawable(d);
+ }
}, mHandler);
actionView.setContentDescription(action.getContentDescription());
if (action.isEnabled()) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index a6cd350b33ce..eb8f065149c8 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -23,6 +23,7 @@ import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
+import com.android.keyguard.KeyguardMessageArea;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
@@ -107,6 +108,11 @@ public class InjectionInflationController {
NotificationStackScrollLayout createNotificationStackScrollLayout();
/**
+ * Creates the KeyguardMessageArea.
+ */
+ KeyguardMessageArea createKeyguardMessageArea();
+
+ /**
* Creates the QSPanel.
*/
QSPanel createQSPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/util/ViewController.java b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
index c7aa780fcacb..64f8dbbb9e34 100644
--- a/packages/SystemUI/src/com/android/systemui/util/ViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/ViewController.java
@@ -23,20 +23,7 @@ import android.view.View.OnAttachStateChangeListener;
* Utility class that handles view lifecycle events for View Controllers.
*
* Implementations should handle setup and teardown related activities inside of
- * {@link #onViewAttached()} and {@link #onViewDetached()}. Be sure to call {@link #init()} on
- * any child controllers that this uses. This can be done in {@link init()} if the controllers
- * are injected, or right after creation time of the child controller.
- *
- * Tip: View "attachment" happens top down - parents are notified that they are attached before
- * any children. That means that if you call a method on a child controller in
- * {@link #onViewAttached()}, the child controller may not have had its onViewAttach method
- * called, so it may not be fully set up.
- *
- * As such, make sure that methods on your controller are safe to call _before_ its {@link #init()}
- * and {@link #onViewAttached()} methods are called. Specifically, if your controller must call
- * {@link View#findViewById(int)} on its root view to setup member variables, do so in its
- * constructor. Save {@link #onViewAttached()} for things that can happen post-construction - adding
- * listeners, dynamically changing content, or other runtime decisions.
+ * {@link #onViewAttached()} and {@link #onViewDetached()}.
*
* @param <T> View class that this ViewController is for.
*/
@@ -67,12 +54,10 @@ public abstract class ViewController<T extends View> {
}
mInited = true;
- if (mView != null) {
- if (mView.isAttachedToWindow()) {
- mOnAttachStateListener.onViewAttachedToWindow(mView);
- }
- mView.addOnAttachStateChangeListener(mOnAttachStateListener);
+ if (mView.isAttachedToWindow()) {
+ mOnAttachStateListener.onViewAttachedToWindow(mView);
}
+ mView.addOnAttachStateChangeListener(mOnAttachStateListener);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a2d6ac8f8511..a3512bec6605 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -86,6 +86,7 @@ public final class WMShell extends SystemUI
private final ProtoTracer mProtoTracer;
private KeyguardUpdateMonitorCallback mSplitScreenKeyguardCallback;
+ private KeyguardUpdateMonitorCallback mPipKeyguardCallback;
private KeyguardUpdateMonitorCallback mOneHandedKeyguardCallback;
@Inject
@@ -140,6 +141,15 @@ public final class WMShell extends SystemUI
pip.showPictureInPictureMenu();
}
});
+ mPipKeyguardCallback = new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ if (showing) {
+ pip.hidePipMenu(null, null);
+ }
+ }
+ };
+ mKeyguardUpdateMonitor.registerCallback(mPipKeyguardCallback);
}
@VisibleForTesting
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index dffad6ccbea5..9be2d124026c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -41,6 +41,8 @@ import android.testing.TestableLooper.RunWithLooper;
import android.testing.ViewUtils;
import android.view.SurfaceControlViewHost;
import android.view.SurfaceView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
import androidx.test.filters.SmallTest;
@@ -65,7 +67,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private ComponentName mComponentName;
private Intent mServiceIntent;
private TestableLooper mTestableLooper;
- private KeyguardSecurityContainer mKeyguardSecurityContainer;
+ private ViewGroup mParent;
@Mock
private Handler mHandler;
@@ -82,8 +84,8 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mKeyguardSecurityContainer = spy(new KeyguardSecurityContainer(mContext));
- ViewUtils.attachView(mKeyguardSecurityContainer);
+ mParent = spy(new FrameLayout(mContext));
+ ViewUtils.attachView(mParent);
mTestableLooper = TestableLooper.get(this);
mComponentName = new ComponentName(mContext, "FakeKeyguardClient.class");
@@ -94,14 +96,13 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
when(mKeyguardClient.queryLocalInterface(anyString())).thenReturn(mKeyguardClient);
when(mKeyguardClient.asBinder()).thenReturn(mKeyguardClient);
- mTestController = new AdminSecondaryLockScreenController.Factory(
- mContext, mKeyguardSecurityContainer, mUpdateMonitor, mHandler)
- .create(mKeyguardCallback);
+ mTestController = new AdminSecondaryLockScreenController(
+ mContext, mParent, mUpdateMonitor, mKeyguardCallback, mHandler);
}
@After
public void tearDown() {
- ViewUtils.detachView(mKeyguardSecurityContainer);
+ ViewUtils.detachView(mParent);
}
@Test
@@ -145,7 +146,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
SurfaceView v = verifySurfaceReady();
mTestController.hide();
- verify(mKeyguardSecurityContainer).removeView(v);
+ verify(mParent).removeView(v);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
@@ -153,7 +154,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
public void testHide_notShown() throws Exception {
mTestController.hide();
// Nothing should happen if trying to hide when the view isn't attached yet.
- verify(mKeyguardSecurityContainer, never()).removeView(any(SurfaceView.class));
+ verify(mParent, never()).removeView(any(SurfaceView.class));
}
@Test
@@ -181,7 +182,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private SurfaceView verifySurfaceReady() throws Exception {
mTestableLooper.processAllMessages();
ArgumentCaptor<SurfaceView> captor = ArgumentCaptor.forClass(SurfaceView.class);
- verify(mKeyguardSecurityContainer).addView(captor.capture());
+ verify(mParent).addView(captor.capture());
mTestableLooper.processAllMessages();
verify(mKeyguardClient).onCreateKeyguardSurface(any(), any(IKeyguardCallback.class));
@@ -189,7 +190,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
}
private void verifyViewDismissed(SurfaceView v) throws Exception {
- verify(mKeyguardSecurityContainer).removeView(v);
+ verify(mParent).removeView(v);
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
deleted file mode 100644
index c2ade81a9877..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.KeyEvent;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase {
-
- @Mock
- private KeyguardAbsKeyInputView mAbsKeyInputView;
- @Mock
- private PasswordTextView mPasswordEntry;
- @Mock
- private KeyguardMessageArea mKeyguardMessageArea;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private SecurityMode mSecurityMode;
- @Mock
- private LockPatternUtils mLockPatternUtils;
- @Mock
- private KeyguardSecurityCallback mKeyguardSecurityCallback;
- @Mock
- private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory;
- @Mock
- private KeyguardMessageAreaController mKeyguardMessageAreaController;
- @Mock
- private LatencyTracker mLatencyTracker;
-
- private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
- .thenReturn(mKeyguardMessageAreaController);
- when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1);
- when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry);
- when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
- when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area))
- .thenReturn(mKeyguardMessageArea);
- mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
- mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mKeyguardMessageAreaControllerFactory, mLatencyTracker) {
- @Override
- void resetState() {
- }
-
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- }
- };
- mKeyguardAbsKeyInputViewController.init();
- reset(mKeyguardMessageAreaController); // Clear out implicit call to init.
- }
-
- @Test
- public void onKeyDown_clearsSecurityMessage() {
- ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor =
- ArgumentCaptor.forClass(KeyDownListener.class);
- verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture());
- onKeyDownListenerArgumentCaptor.getValue().onKeyDown(
- KeyEvent.KEYCODE_0, mock(KeyEvent.class));
- verify(mKeyguardSecurityCallback).userActivity();
- verify(mKeyguardMessageAreaController).setMessage(eq(""));
- }
-
- @Test
- public void onKeyDown_noSecurityMessageInteraction() {
- ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor =
- ArgumentCaptor.forClass(KeyDownListener.class);
- verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture());
- onKeyDownListenerArgumentCaptor.getValue().onKeyDown(
- KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class));
- verifyZeroInteractions(mKeyguardSecurityCallback);
- verifyZeroInteractions(mKeyguardMessageAreaController);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index e7930795c7f8..5999e2cdec78 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -41,9 +41,11 @@ import android.widget.FrameLayout;
import android.widget.TextClock;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.util.InjectionInflationController;
import org.junit.Before;
import org.junit.Test;
@@ -76,7 +78,12 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
.thenReturn(mMockKeyguardSliceView);
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ InjectionInflationController inflationController = new InjectionInflationController(
+ SystemUIFactory.getInstance()
+ .getSysUIComponent()
+ .createViewInstanceCreatorFactory());
+ LayoutInflater layoutInflater = inflationController
+ .injectable(LayoutInflater.from(getContext()));
layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
deleted file mode 100644
index a7197cca530c..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class KeyguardMessageAreaControllerTest extends SysuiTestCase {
- @Mock
- private ConfigurationController mConfigurationController;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private KeyguardMessageArea mKeyguardMessageArea;
-
- private KeyguardMessageAreaController mMessageAreaController;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
- mMessageAreaController = new KeyguardMessageAreaController.Factory(
- mKeyguardUpdateMonitor, mConfigurationController).create(mKeyguardMessageArea);
- }
-
- @Test
- public void onAttachedToWindow_registersConfigurationCallback() {
- ArgumentCaptor<ConfigurationListener> configurationListenerArgumentCaptor =
- ArgumentCaptor.forClass(ConfigurationListener.class);
-
- mMessageAreaController.onViewAttached();
- verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
-
- mMessageAreaController.onViewDetached();
- verify(mConfigurationController).removeCallback(
- eq(configurationListenerArgumentCaptor.getValue()));
- }
-
- @Test
- public void onAttachedToWindow_registersKeyguardUpdateMontiorCallback() {
- ArgumentCaptor<KeyguardUpdateMonitorCallback> keyguardUpdateMonitorCallbackArgumentCaptor =
- ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
-
- mMessageAreaController.onViewAttached();
- verify(mKeyguardUpdateMonitor).registerCallback(
- keyguardUpdateMonitorCallbackArgumentCaptor.capture());
-
- mMessageAreaController.onViewDetached();
- verify(mKeyguardUpdateMonitor).removeCallback(
- eq(keyguardUpdateMonitorCallbackArgumentCaptor.getValue()));
- }
-
- @Test
- public void testClearsTextField() {
- mMessageAreaController.setMessage("");
- verify(mKeyguardMessageArea).setMessage("");
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
index 31fb25a7a89c..fc7b9a4b47d1 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -11,60 +11,65 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
*/
package com.android.keyguard;
-import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class KeyguardMessageAreaTest extends SysuiTestCase {
- private KeyguardMessageArea mKeyguardMessageArea;
+ @Mock
+ private ConfigurationController mConfigurationController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private KeyguardMessageArea mMessageArea;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
- mKeyguardMessageArea.setBouncerVisible(true);
+ mMessageArea = new KeyguardMessageArea(mContext, null, mKeyguardUpdateMonitor,
+ mConfigurationController);
+ waitForIdleSync();
}
@Test
- public void testShowsTextField() {
- mKeyguardMessageArea.setVisibility(View.INVISIBLE);
- mKeyguardMessageArea.setMessage("oobleck");
- assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck");
- }
+ public void onAttachedToWindow_registersConfigurationCallback() {
+ mMessageArea.onAttachedToWindow();
+ verify(mConfigurationController).addCallback(eq(mMessageArea));
- @Test
- public void testHiddenWhenBouncerHidden() {
- mKeyguardMessageArea.setBouncerVisible(false);
- mKeyguardMessageArea.setVisibility(View.INVISIBLE);
- mKeyguardMessageArea.setMessage("oobleck");
- assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
- assertThat(mKeyguardMessageArea.getText()).isEqualTo("oobleck");
+ mMessageArea.onDetachedFromWindow();
+ verify(mConfigurationController).removeCallback(eq(mMessageArea));
}
@Test
- public void testClearsTextField() {
- mKeyguardMessageArea.setVisibility(View.VISIBLE);
- mKeyguardMessageArea.setMessage("");
- assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
- assertThat(mKeyguardMessageArea.getText()).isEqualTo("");
+ public void clearFollowedByMessage_keepsMessage() {
+ mMessageArea.setMessage("");
+ mMessageArea.setMessage("test");
+
+ CharSequence[] messageText = new CharSequence[1];
+ messageText[0] = mMessageArea.getText();
+
+ assertEquals("test", messageText[0]);
}
+
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
deleted file mode 100644
index c69ec1a254c3..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import androidx.test.filters.SmallTest
-import com.android.internal.util.LatencyTracker
-import com.android.internal.widget.LockPatternUtils
-import com.android.internal.widget.LockPatternView
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.`when`
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper
-class KeyguardPatternViewControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var mKeyguardPatternView: KeyguardPatternView
- @Mock
- private lateinit var mKeyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock
- private lateinit var mSecurityMode: KeyguardSecurityModel.SecurityMode
- @Mock
- private lateinit var mLockPatternUtils: LockPatternUtils
- @Mock
- private lateinit var mKeyguardSecurityCallback: KeyguardSecurityCallback
- @Mock
- private lateinit var mLatencyTracker: LatencyTracker
- @Mock
- private lateinit
- var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
- @Mock
- private lateinit var mKeyguardMessageArea: KeyguardMessageArea
- @Mock
- private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
- @Mock
- private lateinit var mLockPatternView: LockPatternView
-
- private lateinit var mKeyguardPatternViewController: KeyguardPatternViewController
-
- @Before
- fun setup() {
- MockitoAnnotations.initMocks(this)
- `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
- `when`(mKeyguardPatternView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area))
- .thenReturn(mKeyguardMessageArea)
- `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
- .thenReturn(mLockPatternView)
- `when`(mKeyguardMessageAreaControllerFactory.create(mKeyguardMessageArea))
- .thenReturn(mKeyguardMessageAreaController)
- mKeyguardPatternViewController = KeyguardPatternViewController(mKeyguardPatternView,
- mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mLatencyTracker, mKeyguardMessageAreaControllerFactory)
- }
-
- @Test
- fun onPause_clearsTextField() {
- mKeyguardPatternViewController.init()
- mKeyguardPatternViewController.onPause()
- verify(mKeyguardMessageAreaController).setMessage("")
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
new file mode 100644
index 000000000000..b4363cf215f1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.keyguard
+
+import androidx.test.filters.SmallTest
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.LayoutInflater
+
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class KeyguardPatternViewTest : SysuiTestCase() {
+
+ private lateinit var mKeyguardPatternView: KeyguardPatternView
+ private lateinit var mSecurityMessage: KeyguardMessageArea
+
+ @Before
+ fun setup() {
+ val inflater = LayoutInflater.from(context)
+ mDependency.injectMockDependency(KeyguardUpdateMonitor::class.java)
+ mKeyguardPatternView = inflater.inflate(R.layout.keyguard_pattern_view, null)
+ as KeyguardPatternView
+ mSecurityMessage = KeyguardMessageArea(mContext, null,
+ mock(KeyguardUpdateMonitor::class.java), mock(ConfigurationController::class.java))
+ mKeyguardPatternView.mSecurityMessageDisplay = mSecurityMessage
+ }
+
+ @Test
+ fun onPause_clearsTextField() {
+ mSecurityMessage.setMessage("an old message")
+ mKeyguardPatternView.onPause()
+ assertThat(mSecurityMessage.text).isEqualTo("")
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
deleted file mode 100644
index 4944284698a0..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
-import android.view.View;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.util.LatencyTracker;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class KeyguardPinBasedInputViewControllerTest extends SysuiTestCase {
-
- @Mock
- private KeyguardPinBasedInputView mPinBasedInputView;
- @Mock
- private PasswordTextView mPasswordEntry;
- @Mock
- private KeyguardMessageArea mKeyguardMessageArea;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private SecurityMode mSecurityMode;
- @Mock
- private LockPatternUtils mLockPatternUtils;
- @Mock
- private KeyguardSecurityCallback mKeyguardSecurityCallback;
- @Mock
- private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory;
- @Mock
- private KeyguardMessageAreaController mKeyguardMessageAreaController;
- @Mock
- private LatencyTracker mLatencyTracker;
- @Mock
- private LiftToActivateListener mLiftToactivateListener;
- @Mock
- private View mDeleteButton;
- @Mock
- private View mOkButton;
-
- private KeyguardPinBasedInputViewController mKeyguardPinViewController;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
- .thenReturn(mKeyguardMessageAreaController);
- when(mPinBasedInputView.getPasswordTextViewId()).thenReturn(1);
- when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
- when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
- when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
- .thenReturn(mKeyguardMessageArea);
- when(mPinBasedInputView.findViewById(R.id.delete_button))
- .thenReturn(mDeleteButton);
- when(mPinBasedInputView.findViewById(R.id.key_enter))
- .thenReturn(mOkButton);
- mKeyguardPinViewController = new KeyguardPinBasedInputViewController(mPinBasedInputView,
- mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
- mKeyguardMessageAreaControllerFactory, mLatencyTracker, mLiftToactivateListener) {
- @Override
- public void onResume(int reason) {
- super.onResume(reason);
- }
- };
- mKeyguardPinViewController.init();
- }
-
- @Test
- public void onResume_requestsFocus() {
- mKeyguardPinViewController.onResume(KeyguardSecurityView.SCREEN_ON);
- verify(mPasswordEntry).requestFocus();
- }
-}
-
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
new file mode 100644
index 000000000000..6666a926c68b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.keyguard;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class KeyguardPinBasedInputViewTest extends SysuiTestCase {
+
+ @Mock
+ private PasswordTextView mPasswordEntry;
+ @Mock
+ private SecurityMessageDisplay mSecurityMessageDisplay;
+ @InjectMocks
+ private KeyguardPinBasedInputView mKeyguardPinView;
+
+ @Before
+ public void setup() {
+ LayoutInflater inflater = LayoutInflater.from(getContext());
+ mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
+ mKeyguardPinView =
+ (KeyguardPinBasedInputView) inflater.inflate(R.layout.keyguard_pin_view, null);
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void onResume_requestsFocus() {
+ mKeyguardPinView.onResume(KeyguardSecurityView.SCREEN_ON);
+ verify(mPasswordEntry).requestFocus();
+ }
+
+ @Test
+ public void onKeyDown_clearsSecurityMessage() {
+ mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_0, mock(KeyEvent.class));
+ verify(mSecurityMessageDisplay).setMessage(eq(""));
+ }
+
+ @Test
+ public void onKeyDown_noSecurityMessageInteraction() {
+ mKeyguardPinView.onKeyDown(KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class));
+ verifyZeroInteractions(mSecurityMessageDisplay);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
index ae159c73b99f..559284ac0672 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java
@@ -31,7 +31,9 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.InjectionInflationController;
import org.junit.After;
import org.junit.Before;
@@ -63,6 +65,7 @@ public class KeyguardPresentationTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
when(mMockKeyguardClockSwitch.getContext()).thenReturn(mContext);
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
@@ -74,7 +77,11 @@ public class KeyguardPresentationTest extends SysuiTestCase {
allowTestableLooperAsMainThread();
- mLayoutInflater = LayoutInflater.from(mContext);
+ InjectionInflationController inflationController = new InjectionInflationController(
+ SystemUIFactory.getInstance()
+ .getSysUIComponent()
+ .createViewInstanceCreatorFactory());
+ mLayoutInflater = inflationController.injectable(LayoutInflater.from(mContext));
mLayoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@Override
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
deleted file mode 100644
index cdb91ecfad89..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.WindowInsetsController;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
-public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
-
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
-
- @Mock
- private KeyguardSecurityContainer mView;
- @Mock
- private AdminSecondaryLockScreenController.Factory mAdminSecondaryLockScreenControllerFactory;
- @Mock
- private AdminSecondaryLockScreenController mAdminSecondaryLockScreenController;
- @Mock
- private LockPatternUtils mLockPatternUtils;
- @Mock
- private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock
- private KeyguardSecurityModel mKeyguardSecurityModel;
- @Mock
- private MetricsLogger mMetricsLogger;
- @Mock
- private UiEventLogger mUiEventLogger;
- @Mock
- private KeyguardStateController mKeyguardStateController;
- @Mock
- private KeyguardInputViewController mInputViewController;
- @Mock
- private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
- @Mock
- private WindowInsetsController mWindowInsetsController;
- @Mock
- private KeyguardSecurityViewFlipper mSecurityViewFlipper;
- @Mock
- private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
-
- private KeyguardSecurityContainerController mKeyguardSecurityContainerController;
-
- @Before
- public void setup() {
- when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
- .thenReturn(mAdminSecondaryLockScreenController);
- when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
-
- mKeyguardSecurityContainerController = new KeyguardSecurityContainerController(
- mView, mAdminSecondaryLockScreenControllerFactory, mLockPatternUtils,
- mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
- mKeyguardStateController, mKeyguardSecurityViewFlipperController);
-
- mKeyguardSecurityContainerController.setSecurityCallback(mSecurityCallback);
- }
-
- @Test
- public void showSecurityScreen_canInflateAllModes() {
- SecurityMode[] modes = SecurityMode.values();
- for (SecurityMode mode : modes) {
- when(mInputViewController.getSecurityMode()).thenReturn(mode);
- mKeyguardSecurityContainerController.showSecurityScreen(mode);
- if (mode == SecurityMode.Invalid) {
- verify(mKeyguardSecurityViewFlipperController, never()).getSecurityView(
- any(SecurityMode.class), any(KeyguardSecurityCallback.class));
- } else {
- verify(mKeyguardSecurityViewFlipperController).getSecurityView(
- eq(mode), any(KeyguardSecurityCallback.class));
- }
- }
- }
-
- @Test
- public void startDisappearAnimation_animatesKeyboard() {
- when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
- SecurityMode.Password);
- when(mInputViewController.getSecurityMode()).thenReturn(
- SecurityMode.Password);
- when(mKeyguardSecurityViewFlipperController.getSecurityView(
- eq(SecurityMode.Password), any(KeyguardSecurityCallback.class)))
- .thenReturn(mInputViewController);
- mKeyguardSecurityContainerController.showPrimarySecurityScreen(false /* turningOff */);
-
- mKeyguardSecurityContainerController.startDisappearAnimation(null);
- verify(mInputViewController).startDisappearAnimation(eq(null));
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 854be1f76722..a867825e223d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -19,19 +19,23 @@ package com.android.keyguard;
import static android.view.WindowInsets.Type.ime;
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.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.LayoutInflater;
import android.view.WindowInsetsController;
import androidx.test.filters.SmallTest;
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Rule;
@@ -46,26 +50,68 @@ import org.mockito.junit.MockitoRule;
@TestableLooper.RunWithLooper()
public class KeyguardSecurityContainerTest extends SysuiTestCase {
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
-
+ @Mock
+ private KeyguardSecurityModel mKeyguardSecurityModel;
+ @Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private KeyguardSecurityContainer.SecurityCallback mSecurityCallback;
+ @Mock
+ private KeyguardSecurityView mSecurityView;
@Mock
private WindowInsetsController mWindowInsetsController;
@Mock
private KeyguardSecurityViewFlipper mSecurityViewFlipper;
-
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
private KeyguardSecurityContainer mKeyguardSecurityContainer;
@Before
public void setup() {
- when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
- mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext());
+ mDependency.injectTestDependency(KeyguardStateController.class, mKeyguardStateController);
+ mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel);
+ mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor);
+ mKeyguardSecurityContainer = new KeyguardSecurityContainer(getContext()) {
+ @Override
+ protected KeyguardSecurityView getSecurityView(
+ KeyguardSecurityModel.SecurityMode securityMode) {
+ return mSecurityView;
+ }
+ };
mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
+ when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
+ mKeyguardSecurityContainer.setSecurityCallback(mSecurityCallback);
+ }
+
+ @Test
+ public void showSecurityScreen_canInflateAllModes() {
+ Context context = getContext();
+
+ for (int theme : new int[] {R.style.Theme_SystemUI, R.style.Theme_SystemUI_Light}) {
+ context.setTheme(theme);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ KeyguardSecurityModel.SecurityMode[] modes =
+ KeyguardSecurityModel.SecurityMode.values();
+ for (KeyguardSecurityModel.SecurityMode mode : modes) {
+ final int resId = mKeyguardSecurityContainer.getLayoutIdFor(mode);
+ if (resId == 0) {
+ continue;
+ }
+ inflater.inflate(resId, null /* root */, false /* attach */);
+ }
+ }
}
@Test
public void startDisappearAnimation_animatesKeyboard() {
- mKeyguardSecurityContainer.startDisappearAnimation(SecurityMode.Password);
+ when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
+ KeyguardSecurityModel.SecurityMode.Password);
+ mKeyguardSecurityContainer.showPrimarySecurityScreen(false /* turningOff */);
+
+ mKeyguardSecurityContainer.startDisappearAnimation(null);
+ verify(mSecurityView).startDisappearAnimation(eq(null));
verify(mWindowInsetsController).controlWindowInsetsAnimation(eq(ime()), anyLong(), any(),
any(), any());
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
deleted file mode 100644
index 3b7f4b839853..000000000000
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.keyguard;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-import android.view.WindowInsetsController;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
-public class KeyguardSecurityViewFlipperControllerTest extends SysuiTestCase {
-
- @Rule
- public MockitoRule mRule = MockitoJUnit.rule();
-
- @Mock
- private KeyguardSecurityViewFlipper mView;
- @Mock
- private LayoutInflater mLayoutInflater;
- @Mock
- private KeyguardInputViewController.Factory mKeyguardSecurityViewControllerFactory;
- @Mock
- private KeyguardInputViewController mKeyguardInputViewController;
- @Mock
- private KeyguardInputView mInputView;
- @Mock
- private WindowInsetsController mWindowInsetsController;
- @Mock
- private KeyguardSecurityCallback mKeyguardSecurityCallback;
-
- private KeyguardSecurityViewFlipperController mKeyguardSecurityViewFlipperController;
-
- @Before
- public void setup() {
- when(mKeyguardSecurityViewControllerFactory.create(
- any(KeyguardInputView.class), any(SecurityMode.class),
- any(KeyguardSecurityCallback.class)))
- .thenReturn(mKeyguardInputViewController);
- when(mView.getWindowInsetsController()).thenReturn(mWindowInsetsController);
-
- mKeyguardSecurityViewFlipperController = new KeyguardSecurityViewFlipperController(mView,
- mLayoutInflater, mKeyguardSecurityViewControllerFactory);
- }
-
- @Test
- public void showSecurityScreen_canInflateAllModes() {
- SecurityMode[] modes = SecurityMode.values();
- // Always return an invalid controller so that we're always making a new one.
- when(mKeyguardInputViewController.getSecurityMode()).thenReturn(SecurityMode.Invalid);
- for (SecurityMode mode : modes) {
- reset(mLayoutInflater);
- when(mLayoutInflater.inflate(anyInt(), eq(mView), eq(false)))
- .thenReturn(mInputView);
- mKeyguardSecurityViewFlipperController.getSecurityView(mode, mKeyguardSecurityCallback);
- if (mode == SecurityMode.Invalid || mode == SecurityMode.None) {
- verify(mLayoutInflater, never()).inflate(
- anyInt(), any(ViewGroup.class), anyBoolean());
- } else {
- verify(mLayoutInflater).inflate(anyInt(), eq(mView), eq(false));
- }
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
index 79ec4f2c553a..0431704778c3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java
@@ -24,7 +24,9 @@ import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.InjectionInflationController;
import org.junit.Before;
import org.junit.Test;
@@ -48,7 +50,13 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Before
public void setUp() {
allowTestableLooperAsMainThread();
- LayoutInflater layoutInflater = LayoutInflater.from(getContext());
+ mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
+ InjectionInflationController inflationController = new InjectionInflationController(
+ SystemUIFactory.getInstance()
+ .getSysUIComponent()
+ .createViewInstanceCreatorFactory());
+ LayoutInflater layoutInflater = inflationController
+ .injectable(LayoutInflater.from(getContext()));
mKeyguardStatusView =
(KeyguardStatusView) layoutInflater.inflate(R.layout.keyguard_status_view, null);
org.mockito.MockitoAnnotations.initMocks(this);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 42b21c61510a..27b5b7fda684 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -36,7 +36,6 @@ import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
@@ -55,7 +54,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
// Mock
private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
-
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
private ShadeController mShadeController = mock(ShadeController.class);
@@ -157,30 +155,6 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
verify(mMediaOutputBaseAdapter).notifyDataSetChanged();
}
- @Test
- public void refresh_with6Devices_checkBottomPaddingVisibility() {
- for (int i = 0; i < 6; i++) {
- mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
- }
- mMediaOutputBaseDialogImpl.refresh();
- final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
- R.id.list_bottom_padding);
-
- assertThat(view.getVisibility()).isEqualTo(View.GONE);
- }
-
- @Test
- public void refresh_with5Devices_checkBottomPaddingVisibility() {
- for (int i = 0; i < 5; i++) {
- mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
- }
- mMediaOutputBaseDialogImpl.refresh();
- final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
- R.id.list_bottom_padding);
-
- assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
- }
-
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
@@ -189,24 +163,34 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
mAdapter = mMediaOutputBaseAdapter;
}
+ @Override
int getHeaderIconRes() {
return mHeaderIconRes;
}
+ @Override
IconCompat getHeaderIcon() {
return mIconCompat;
}
+ @Override
int getHeaderIconSize() {
return 10;
}
+ @Override
CharSequence getHeaderText() {
return mHeaderTitle;
}
+ @Override
CharSequence getHeaderSubtitle() {
return mHeaderSubtitle;
}
+
+ @Override
+ int getStopButtonVisibility() {
+ return 0;
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
new file mode 100644
index 000000000000..ca328fbe44fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.MediaRoute2Info;
+import android.media.session.MediaSessionManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.ShadeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MediaOutputDialogTest extends SysuiTestCase {
+
+ private static final String TEST_PACKAGE = "test_package";
+
+ // Mock
+ private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
+ private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+ private ShadeController mShadeController = mock(ShadeController.class);
+ private ActivityStarter mStarter = mock(ActivityStarter.class);
+ private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
+ private MediaDevice mMediaDevice = mock(MediaDevice.class);
+
+ private MediaOutputDialog mMediaOutputDialog;
+ private MediaOutputController mMediaOutputController;
+ private List<String> mFeatures = new ArrayList<>();
+
+ @Before
+ public void setUp() {
+ mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+ mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter);
+ mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
+ mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController);
+
+ when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
+ when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
+ }
+
+ @Test
+ public void getStopButtonVisibility_remoteDevice_returnVisible() {
+ mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK);
+
+ assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+ mFeatures.clear();
+ mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK);
+
+ assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+ mFeatures.clear();
+ mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK);
+
+ assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+ mFeatures.clear();
+ mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+
+ assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void getStopButtonVisibility_localDevice_returnGone() {
+ mFeatures.add(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK);
+
+ assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
+ }
+
+}
diff --git a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
index f6eb40a842d5..94c871d8a366 100644
--- a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -17,18 +17,63 @@
#include <errno.h>
#include <error.h>
#include <jni.h>
+#include <linux/filter.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/JNIHelpCompat.h>
#include <nativehelper/ScopedUtfChars.h>
#include <net/if.h>
+#include <netinet/ether.h>
+#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
+#include <stdio.h>
#define LOG_TAG "TetheringUtils"
#include <android/log.h>
namespace android {
+static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
+static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
+static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+
+static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
+ sock_filter filter_code[] = {
+ // Check header is ICMPv6.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
+
+ // Check ICMPv6 type.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+
+ const sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT);
+}
+
+static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT);
+}
+
static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
jint ifIndex)
{
@@ -125,7 +170,12 @@ static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject j
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
+ { "setupNaSocket", "(Ljava/io/FileDescriptor;)V",
+ (void*) android_net_util_setupNaSocket },
+ { "setupNsSocket", "(Ljava/io/FileDescriptor;)V",
+ (void*) android_net_util_setupNsSocket },
+ { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V",
+ (void*) android_net_util_setupRaSocket },
};
int register_android_net_util_TetheringUtils(JNIEnv* env) {
diff --git a/packages/Tethering/src/android/net/ip/DadProxy.java b/packages/Tethering/src/android/net/ip/DadProxy.java
new file mode 100644
index 000000000000..e2976b78908c
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/DadProxy.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import android.net.util.InterfaceParams;
+import android.os.Handler;
+
+import androidx.annotation.VisibleForTesting;
+
+/**
+ * Basic Duplicate address detection proxy.
+ *
+ * @hide
+ */
+public class DadProxy {
+ private static final String TAG = DadProxy.class.getSimpleName();
+
+ @VisibleForTesting
+ public static NeighborPacketForwarder naForwarder;
+ public static NeighborPacketForwarder nsForwarder;
+
+ public DadProxy(Handler h, InterfaceParams tetheredIface) {
+ naForwarder = new NeighborPacketForwarder(h, tetheredIface,
+ NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+ nsForwarder = new NeighborPacketForwarder(h, tetheredIface,
+ NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+ }
+
+ /** Stop NS/NA Forwarders. */
+ public void stop() {
+ naForwarder.stop();
+ nsForwarder.stop();
+ }
+
+ /** Set upstream iface on both forwarders. */
+ public void setUpstreamIface(InterfaceParams upstreamIface) {
+ naForwarder.setUpstreamIface(upstreamIface);
+ nsForwarder.setUpstreamIface(upstreamIface);
+ }
+}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 673cbf09d259..336124dc1b90 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -51,6 +51,7 @@ import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -160,6 +161,15 @@ public class IpServer extends StateMachine {
/** Capture IpServer dependencies, for injection. */
public abstract static class Dependencies {
+ /**
+ * Create a DadProxy instance to be used by IpServer.
+ * To support multiple tethered interfaces concurrently DAD Proxy
+ * needs to be supported per IpServer instead of per upstream.
+ */
+ public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) {
+ return new DadProxy(handler, ifParams);
+ }
+
/** Create an IpNeighborMonitor to be used by this IpServer */
public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
IpNeighborMonitor.NeighborEventConsumer consumer) {
@@ -256,6 +266,7 @@ public class IpServer extends StateMachine {
// Advertisements (otherwise, we do not add them to mLinkProperties at all).
private LinkProperties mLastIPv6LinkProperties;
private RouterAdvertisementDaemon mRaDaemon;
+ private DadProxy mDadProxy;
// To be accessed only on the handler thread
private int mDhcpServerStartIndex = 0;
@@ -674,6 +685,13 @@ public class IpServer extends StateMachine {
return false;
}
+ // TODO: use ShimUtils instead of explicitly checking the version here.
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
+ || "T".equals(Build.VERSION.CODENAME)) {
+ // DAD Proxy starts forwarding packets after IPv6 upstream is present.
+ mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams);
+ }
+
return true;
}
@@ -685,6 +703,11 @@ public class IpServer extends StateMachine {
mRaDaemon.stop();
mRaDaemon = null;
}
+
+ if (mDadProxy != null) {
+ mDadProxy.stop();
+ mDadProxy = null;
+ }
}
// IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
@@ -702,11 +725,16 @@ public class IpServer extends StateMachine {
}
RaParams params = null;
- int upstreamIfindex = 0;
+ String upstreamIface = null;
+ InterfaceParams upstreamIfaceParams = null;
+ int upstreamIfIndex = 0;
if (v6only != null) {
- final String upstreamIface = v6only.getInterfaceName();
-
+ upstreamIface = v6only.getInterfaceName();
+ upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface);
+ if (upstreamIfaceParams != null) {
+ upstreamIfIndex = upstreamIfaceParams.index;
+ }
params = new RaParams();
params.mtu = v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
@@ -726,15 +754,13 @@ public class IpServer extends StateMachine {
}
}
- upstreamIfindex = mDeps.getIfindex(upstreamIface);
-
// Add upstream index to name mapping for the tether stats usage in the coordinator.
// Although this mapping could be added by both class Tethering and IpServer, adding
// mapping from IpServer guarantees that the mapping is added before the adding
// forwarding rules. That is because there are different state machines in both
// classes. It is hard to guarantee the link property update order between multiple
// state machines.
- mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface);
+ mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
}
// If v6only is null, we pass in null to setRaParams(), which handles
@@ -743,8 +769,11 @@ public class IpServer extends StateMachine {
setRaParams(params);
mLastIPv6LinkProperties = v6only;
- updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfindex, null);
- mLastIPv6UpstreamIfindex = upstreamIfindex;
+ updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
+ mLastIPv6UpstreamIfindex = upstreamIfIndex;
+ if (mDadProxy != null) {
+ mDadProxy.setUpstreamIface(upstreamIfaceParams);
+ }
}
private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
new file mode 100644
index 000000000000..73fc833fabf5
--- /dev/null
+++ b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_PACKET;
+import static android.system.OsConstants.ETH_P_IPV6;
+import static android.system.OsConstants.IPPROTO_RAW;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_NONBLOCK;
+import static android.system.OsConstants.SOCK_RAW;
+
+import android.net.util.InterfaceParams;
+import android.net.util.PacketReader;
+import android.net.util.SocketUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+
+/**
+ * Basic IPv6 Neighbor Advertisement Forwarder.
+ *
+ * Forward NA packets from upstream iface to tethered iface
+ * and NS packets from tethered iface to upstream iface.
+ *
+ * @hide
+ */
+public class NeighborPacketForwarder extends PacketReader {
+ private final String mTag;
+
+ private FileDescriptor mFd;
+
+ // TODO: get these from NetworkStackConstants.
+ private static final int IPV6_ADDR_LEN = 16;
+ private static final int IPV6_DST_ADDR_OFFSET = 24;
+ private static final int IPV6_HEADER_LEN = 40;
+ private static final int ETH_HEADER_LEN = 14;
+
+ private InterfaceParams mListenIfaceParams, mSendIfaceParams;
+
+ private final int mType;
+ public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
+ public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
+
+ public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) {
+ super(h);
+ mTag = NeighborPacketForwarder.class.getSimpleName() + "-"
+ + tetheredInterface.name + "-" + type;
+ mType = type;
+
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ mSendIfaceParams = tetheredInterface;
+ } else {
+ mListenIfaceParams = tetheredInterface;
+ }
+ }
+
+ /** Set new upstream iface and start/stop based on new params. */
+ public void setUpstreamIface(InterfaceParams upstreamParams) {
+ final InterfaceParams oldUpstreamParams;
+
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ oldUpstreamParams = mListenIfaceParams;
+ mListenIfaceParams = upstreamParams;
+ } else {
+ oldUpstreamParams = mSendIfaceParams;
+ mSendIfaceParams = upstreamParams;
+ }
+
+ if (oldUpstreamParams == null && upstreamParams != null) {
+ start();
+ } else if (oldUpstreamParams != null && upstreamParams == null) {
+ stop();
+ } else if (oldUpstreamParams != null && upstreamParams != null
+ && oldUpstreamParams.index != upstreamParams.index) {
+ stop();
+ start();
+ }
+ }
+
+ // TODO: move NetworkStackUtils.closeSocketQuietly to
+ // frameworks/libs/net/common/device/com/android/net/module/util/[someclass].
+ private void closeSocketQuietly(FileDescriptor fd) {
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ignored) {
+ }
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ try {
+ // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used.
+ // To keep uniformity in both directions PACKET socket can be used.
+ mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+
+ // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type?
+ if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ TetheringUtils.setupNaSocket(mFd);
+ } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) {
+ TetheringUtils.setupNsSocket(mFd);
+ }
+
+ SocketAddress bindAddress = SocketUtils.makePacketSocketAddress(
+ ETH_P_IPV6, mListenIfaceParams.index);
+ Os.bind(mFd, bindAddress);
+ } catch (ErrnoException | SocketException e) {
+ Log.wtf(mTag, "Failed to create socket", e);
+ closeSocketQuietly(mFd);
+ return null;
+ }
+
+ return mFd;
+ }
+
+ private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) {
+ Inet6Address dstAddr;
+ try {
+ dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf,
+ IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN));
+ } catch (UnknownHostException | ClassCastException impossible) {
+ throw new AssertionError("16-byte array not valid IPv6 address?");
+ }
+ return dstAddr;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ if (mSendIfaceParams == null) {
+ return;
+ }
+
+ // The BPF filter should already have checked the length of the packet, but...
+ if (length < IPV6_HEADER_LEN) {
+ return;
+ }
+ Inet6Address destv6 = getIpv6DestinationAddress(recvbuf);
+ if (!destv6.isMulticastAddress()) {
+ return;
+ }
+ InetSocketAddress dest = new InetSocketAddress(destv6, 0);
+
+ FileDescriptor fd = null;
+ try {
+ fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
+ SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name);
+
+ int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest);
+ } catch (ErrnoException | SocketException e) {
+ Log.e(mTag, "handlePacket error: " + e);
+ } finally {
+ closeSocketQuietly(fd);
+ }
+ }
+}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 6f017dcb623f..7c0b7cc7515c 100644
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -18,6 +18,7 @@ package android.net.ip;
import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
+import static android.net.util.TetheringUtils.getAllNodesForScopeId;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.SOCK_RAW;
@@ -44,7 +45,6 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
-import java.net.UnknownHostException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -92,10 +92,6 @@ public class RouterAdvertisementDaemon {
private static final int DAY_IN_SECONDS = 86_400;
- private static final byte[] ALL_NODES = new byte[] {
- (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
- };
-
private final InterfaceParams mInterface;
private final InetSocketAddress mAllNodes;
@@ -240,7 +236,6 @@ public class RouterAdvertisementDaemon {
}
}
-
public RouterAdvertisementDaemon(InterfaceParams ifParams) {
mInterface = ifParams;
mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
@@ -363,15 +358,6 @@ public class RouterAdvertisementDaemon {
}
}
- private static Inet6Address getAllNodesForScopeId(int scopeId) {
- try {
- return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
- } catch (UnknownHostException uhe) {
- Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe);
- return null;
- }
- }
-
private static byte asByte(int value) {
return (byte) value;
}
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
index b17b4ba77cfb..53b54f7de05d 100644
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -17,11 +17,15 @@ package android.net.util;
import android.net.TetherStatsParcel;
import android.net.TetheringRequestParcel;
+import android.util.Log;
import androidx.annotation.NonNull;
import java.io.FileDescriptor;
+import java.net.Inet6Address;
import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -30,6 +34,24 @@ import java.util.Objects;
* {@hide}
*/
public class TetheringUtils {
+ public static final byte[] ALL_NODES = new byte[] {
+ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+ };
+
+ /**
+ * Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void setupNaSocket(FileDescriptor fd)
+ throws SocketException;
+
+ /**
+ * Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
+ * @param fd the socket's {@link FileDescriptor}.
+ */
+ public static native void setupNsSocket(FileDescriptor fd)
+ throws SocketException;
+
/**
* The object which records offload Tx/Rx forwarded bytes/packets.
* TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
@@ -129,4 +151,15 @@ public class TetheringUtils {
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
&& request.showProvisioningUi == otherRequest.showProvisioningUi;
}
+
+ /** Get inet6 address for all nodes given scope ID. */
+ public static Inet6Address getAllNodesForScopeId(int scopeId) {
+ try {
+ return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
+ } catch (UnknownHostException uhe) {
+ Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
+ + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
+ return null;
+ }
+ }
}
diff --git a/packages/Tethering/tests/privileged/Android.bp b/packages/Tethering/tests/privileged/Android.bp
index a0fb24603a93..9217345dc2f5 100644
--- a/packages/Tethering/tests/privileged/Android.bp
+++ b/packages/Tethering/tests/privileged/Android.bp
@@ -14,8 +14,22 @@
// limitations under the License.
//
+java_defaults {
+ name: "TetheringPrivilegedTestsJniDefaults",
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ "libtetherutilsjni",
+ ],
+ jni_uses_sdk_apis: true,
+ visibility: ["//visibility:private"],
+}
+
android_test {
name: "TetheringPrivilegedTests",
+ defaults: [
+ "TetheringPrivilegedTestsJniDefaults",
+ ],
srcs: [
"src/**/*.java",
"src/**/*.kt",
@@ -23,8 +37,13 @@ android_test {
certificate: "networkstack",
platform_apis: true,
test_suites: [
- "general-tests",
+ "device-tests",
"mts",
],
+ static_libs: [
+ "androidx.test.rules",
+ "net-tests-utils",
+ "TetheringApiCurrentLib",
+ ],
compile_multilib: "both",
}
diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
new file mode 100644
index 000000000000..747d3e803026
--- /dev/null
+++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
+
+import static com.android.internal.util.BitUtils.uint16;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.net.INetd;
+import android.net.InetAddresses;
+import android.net.MacAddress;
+import android.net.TestNetworkInterface;
+import android.net.TestNetworkManager;
+import android.net.util.InterfaceParams;
+import android.net.util.IpUtils;
+import android.net.util.TetheringUtils;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.system.ErrnoException;
+import android.system.Os;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.TapPacketReader;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DadProxyTest {
+ private static final int DATA_BUFFER_LEN = 4096;
+ private static final int PACKET_TIMEOUT_MS = 5_000;
+
+ // TODO: make NetworkStackConstants accessible to this test and use the constant from there.
+ private static final int ETHER_SRC_ADDR_OFFSET = 6;
+
+ private DadProxy mProxy;
+ TestNetworkInterface mUpstreamTestIface, mTetheredTestIface;
+ private InterfaceParams mUpstreamParams, mTetheredParams;
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader;
+ private FileDescriptor mUpstreamTapFd, mTetheredTapFd;
+
+ private static INetd sNetd;
+
+ @BeforeClass
+ public static void setupOnce() {
+ System.loadLibrary("tetherutilsjni");
+
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ final IBinder netdIBinder =
+ (IBinder) inst.getContext().getSystemService(Context.NETD_SERVICE);
+ sNetd = INetd.Stub.asInterface(netdIBinder);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mHandlerThread = new HandlerThread(getClass().getSimpleName());
+ mHandlerThread.start();
+ mHandler = new Handler(mHandlerThread.getLooper());
+
+ setupTapInterfaces();
+
+ // Looper must be prepared here since AndroidJUnitRunner runs tests on separate threads.
+ if (Looper.myLooper() == null) Looper.prepare();
+
+ DadProxy mProxy = setupProxy();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mHandlerThread != null) {
+ mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket
+ mHandler.post(mTetheredPacketReader::stop); // Also closes the socket
+ mUpstreamTapFd = null;
+ mTetheredTapFd = null;
+ mHandlerThread.quitSafely();
+ }
+
+ if (mTetheredParams != null) {
+ sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+ }
+ if (mUpstreamParams != null) {
+ sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+ }
+
+ if (mUpstreamTestIface != null) {
+ try {
+ Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor());
+ } catch (ErrnoException e) { }
+ }
+
+ if (mTetheredTestIface != null) {
+ try {
+ Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor());
+ } catch (ErrnoException e) { }
+ }
+ }
+
+ private TestNetworkInterface setupTapInterface() {
+ final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+ AtomicReference<TestNetworkInterface> iface = new AtomicReference<>();
+
+ inst.getUiAutomation().adoptShellPermissionIdentity();
+ try {
+ final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService(
+ Context.TEST_NETWORK_SERVICE);
+ iface.set(tnm.createTapInterface());
+ } finally {
+ inst.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ return iface.get();
+ }
+
+ private void setupTapInterfaces() {
+ // Create upstream test iface.
+ mUpstreamTestIface = setupTapInterface();
+ mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName());
+ assertNotNull(mUpstreamParams);
+ mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor();
+ mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd,
+ DATA_BUFFER_LEN);
+ mHandler.post(mUpstreamPacketReader::start);
+
+ // Create tethered test iface.
+ mTetheredTestIface = setupTapInterface();
+ mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName());
+ assertNotNull(mTetheredParams);
+ mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor();
+ mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd,
+ DATA_BUFFER_LEN);
+ mHandler.post(mTetheredPacketReader::start);
+ }
+
+ private static final int IPV6_HEADER_LEN = 40;
+ private static final int ETH_HEADER_LEN = 14;
+ private static final int ICMPV6_NA_NS_LEN = 24;
+ private static final int LL_TARGET_OPTION_LEN = 8;
+ private static final int ICMPV6_CHECKSUM_OFFSET = 2;
+ private static final int ETHER_TYPE_IPV6 = 0x86dd;
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static int checksumFold(int sum) {
+ while (sum > 0xffff) {
+ sum = (sum >> 16) + (sum & 0xffff);
+ }
+ return sum;
+ }
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static short checksumAdjust(short checksum, short oldWord, short newWord) {
+ checksum = (short) ~checksum;
+ int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord));
+ return (short) ~tempSum;
+ }
+
+ // TODO: move the IpUtils code to frameworks/lib/net and link it statically.
+ private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset,
+ int transportLen) {
+ // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses
+ // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental
+ // checksum adjustment for the change in the next header byte.
+ short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen);
+ return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6);
+ }
+
+ private static ByteBuffer createDadPacket(int type) {
+ // Refer to buildArpPacket()
+ int icmpLen = ICMPV6_NA_NS_LEN
+ + (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT
+ ? LL_TARGET_OPTION_LEN : 0);
+ final ByteBuffer buf = ByteBuffer.allocate(icmpLen + IPV6_HEADER_LEN + ETH_HEADER_LEN);
+
+ // Ethernet header.
+ final MacAddress srcMac = MacAddress.fromString("33:33:ff:66:77:88");
+ buf.put(srcMac.toByteArray());
+ final MacAddress dstMac = MacAddress.fromString("01:02:03:04:05:06");
+ buf.put(dstMac.toByteArray());
+ buf.putShort((short) ETHER_TYPE_IPV6);
+
+ // IPv6 header
+ byte[] version = {(byte) 0x60, 0x00, 0x00, 0x00};
+ buf.put(version); // Version
+ buf.putShort((byte) icmpLen); // Length
+ buf.put((byte) IPPROTO_ICMPV6); // Next header
+ buf.put((byte) 0xff); // Hop limit
+
+ final byte[] target =
+ InetAddresses.parseNumericAddress("fe80::1122:3344:5566:7788").getAddress();
+ final byte[] src;
+ final byte[] dst;
+ if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION) {
+ src = InetAddresses.parseNumericAddress("::").getAddress();
+ dst = InetAddresses.parseNumericAddress("ff02::1:ff66:7788").getAddress();
+ } else {
+ src = target;
+ dst = TetheringUtils.ALL_NODES;
+ }
+ buf.put(src);
+ buf.put(dst);
+
+ // ICMPv6 Header
+ buf.put((byte) type); // Type
+ buf.put((byte) 0x00); // Code
+ buf.putShort((short) 0); // Checksum
+ buf.putInt(0); // Reserved
+ buf.put(target);
+
+ if (type == NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT) {
+ //NA packet has LL target address
+ //ICMPv6 Option
+ buf.put((byte) 0x02); // Type
+ buf.put((byte) 0x01); // Length
+ byte[] ll_target = MacAddress.fromString("01:02:03:04:05:06").toByteArray();
+ buf.put(ll_target);
+ }
+
+ // Populate checksum field
+ final int transportOffset = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+ final short checksum = icmpv6Checksum(buf, ETH_HEADER_LEN, transportOffset, icmpLen);
+ buf.putShort(transportOffset + ICMPV6_CHECKSUM_OFFSET, checksum);
+
+ buf.flip();
+ return buf;
+ }
+
+ private DadProxy setupProxy() throws Exception {
+ DadProxy proxy = new DadProxy(mHandler, mTetheredParams);
+ mHandler.post(() -> proxy.setUpstreamIface(mUpstreamParams));
+
+ // Upstream iface is added to local network to simplify test case.
+ // Otherwise the test needs to create and destroy a network for the upstream iface.
+ sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name);
+ sNetd.networkAddInterface(INetd.LOCAL_NET_ID, mTetheredParams.name);
+
+ return proxy;
+ }
+
+ // TODO: change to assert.
+ private boolean waitForPacket(ByteBuffer packet, TapPacketReader reader) {
+ byte[] p;
+
+ while ((p = reader.popPacket(PACKET_TIMEOUT_MS)) != null) {
+ final ByteBuffer buffer = ByteBuffer.wrap(p);
+
+ if (buffer.compareTo(packet) == 0) return true;
+ }
+ return false;
+ }
+
+ private void updateDstMac(ByteBuffer buf, MacAddress mac) {
+ buf.put(mac.toByteArray());
+ buf.rewind();
+ }
+ private void updateSrcMac(ByteBuffer buf, InterfaceParams ifaceParams) {
+ buf.position(ETHER_SRC_ADDR_OFFSET);
+ buf.put(ifaceParams.macAddr.toByteArray());
+ buf.rewind();
+ }
+
+ @Test
+ public void testNaForwardingFromUpstreamToTether() throws Exception {
+ ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+ mUpstreamPacketReader.sendResponse(na);
+ updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+ updateSrcMac(na, mTetheredParams);
+ assertTrue(waitForPacket(na, mTetheredPacketReader));
+ }
+
+ @Test
+ // TODO: remove test once DAD works in both directions.
+ public void testNaForwardingFromTetherToUpstream() throws Exception {
+ ByteBuffer na = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
+
+ mTetheredPacketReader.sendResponse(na);
+ updateDstMac(na, MacAddress.fromString("33:33:00:00:00:01"));
+ updateSrcMac(na, mTetheredParams);
+ assertFalse(waitForPacket(na, mUpstreamPacketReader));
+ }
+
+ @Test
+ public void testNsForwardingFromTetherToUpstream() throws Exception {
+ ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+ mTetheredPacketReader.sendResponse(ns);
+ updateSrcMac(ns, mUpstreamParams);
+ assertTrue(waitForPacket(ns, mUpstreamPacketReader));
+ }
+
+ @Test
+ // TODO: remove test once DAD works in both directions.
+ public void testNsForwardingFromUpstreamToTether() throws Exception {
+ ByteBuffer ns = createDadPacket(NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
+
+ mUpstreamPacketReader.sendResponse(ns);
+ updateSrcMac(ns, mUpstreamParams);
+ assertFalse(waitForPacket(ns, mTetheredPacketReader));
+ }
+}
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3b72b5b47191..1a976adc60e0 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -86,6 +86,7 @@ import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
+import android.os.Build;
import android.os.Handler;
import android.os.RemoteException;
import android.os.test.TestLooper;
@@ -100,8 +101,12 @@ import com.android.networkstack.tethering.BpfCoordinator;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
import com.android.networkstack.tethering.TetheringConfiguration;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -120,6 +125,9 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class IpServerTest {
+ @Rule
+ public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
+
private static final String IFACE_NAME = "testnet1";
private static final String UPSTREAM_IFACE = "upstream0";
private static final String UPSTREAM_IFACE2 = "upstream1";
@@ -132,6 +140,11 @@ public class IpServerTest {
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+ private static final InterfaceParams UPSTREAM_IFACE_PARAMS = new InterfaceParams(
+ UPSTREAM_IFACE, UPSTREAM_IFINDEX, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
+ private static final InterfaceParams UPSTREAM_IFACE_PARAMS2 = new InterfaceParams(
+ UPSTREAM_IFACE2, UPSTREAM_IFINDEX2, MacAddress.ALL_ZEROS_ADDRESS,
+ 1500 /* defaultMtu */);
private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000;
@@ -142,6 +155,7 @@ public class IpServerTest {
@Mock private IpServer.Callback mCallback;
@Mock private SharedLog mSharedLog;
@Mock private IDhcpServer mDhcpServer;
+ @Mock private DadProxy mDadProxy;
@Mock private RouterAdvertisementDaemon mRaDaemon;
@Mock private IpNeighborMonitor mIpNeighborMonitor;
@Mock private IpServer.Dependencies mDependencies;
@@ -165,8 +179,11 @@ public class IpServerTest {
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
boolean usingBpfOffload) throws Exception {
+ when(mDependencies.getDadProxy(any(), any())).thenReturn(mDadProxy);
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
+ when(mDependencies.getInterfaceParams(UPSTREAM_IFACE)).thenReturn(UPSTREAM_IFACE_PARAMS);
+ when(mDependencies.getInterfaceParams(UPSTREAM_IFACE2)).thenReturn(UPSTREAM_IFACE_PARAMS2);
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE))).thenReturn(UPSTREAM_IFINDEX);
when(mDependencies.getIfindex(eq(UPSTREAM_IFACE2))).thenReturn(UPSTREAM_IFINDEX2);
@@ -1103,4 +1120,78 @@ public class IpServerTest {
}
return true;
}
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void dadProxyUpdates() throws Exception {
+ InOrder inOrder = inOrder(mDadProxy);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Add an upstream without IPv6.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // Add IPv6 to the upstream.
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Change upstream.
+ // New linkproperties is needed, otherwise changing the iface has no impact.
+ LinkProperties lp2 = new LinkProperties();
+ lp2.setInterfaceName(UPSTREAM_IFACE2);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp2, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS2);
+
+ // Lose IPv6 on the upstream...
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // ... and regain it on a different upstream.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Lose upstream.
+ dispatchTetherConnectionChanged(null, null, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(null);
+
+ // Regain upstream.
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, 0);
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+
+ // Stop tethering.
+ mIpServer.stop();
+ mLooper.dispatchAll();
+ }
+
+ private void checkDadProxyEnabled(boolean expectEnabled) throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+ InOrder inOrder = inOrder(mDadProxy);
+ // Add IPv6 to the upstream.
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(UPSTREAM_IFACE);
+ if (expectEnabled) {
+ inOrder.verify(mDadProxy).setUpstreamIface(UPSTREAM_IFACE_PARAMS);
+ } else {
+ inOrder.verifyNoMoreInteractions();
+ }
+ // Stop tethering.
+ mIpServer.stop();
+ mLooper.dispatchAll();
+ if (expectEnabled) {
+ inOrder.verify(mDadProxy).stop();
+ }
+ else {
+ verify(mDependencies, never()).getDadProxy(any(), any());
+ }
+ }
+ @Test @IgnoreAfter(Build.VERSION_CODES.R)
+ public void testDadProxyUpdates_DisabledUpToR() throws Exception {
+ checkDadProxyEnabled(false);
+ }
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testDadProxyUpdates_EnabledAfterR() throws Exception {
+ checkDadProxyEnabled(true);
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 1fe3840b51a8..df570206e389 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -110,6 +110,7 @@ import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
+import android.net.ip.DadProxy;
import android.net.ip.IpNeighborMonitor;
import android.net.ip.IpServer;
import android.net.ip.RouterAdvertisementDaemon;
@@ -196,6 +197,7 @@ public class TetheringTest {
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private UpstreamNetworkMonitor mUpstreamNetworkMonitor;
@Mock private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+ @Mock private DadProxy mDadProxy;
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
@Mock private IpNeighborMonitor mIpNeighborMonitor;
@Mock private IDhcpServer mDhcpServer;
@@ -280,6 +282,12 @@ public class TetheringTest {
public class MockIpServerDependencies extends IpServer.Dependencies {
@Override
+ public DadProxy getDadProxy(
+ Handler handler, InterfaceParams ifParams) {
+ return mDadProxy;
+ }
+
+ @Override
public RouterAdvertisementDaemon getRouterAdvertisementDaemon(
InterfaceParams ifParams) {
return mRouterAdvertisementDaemon;
@@ -832,6 +840,7 @@ public class TetheringTest {
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, never()).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, never()).buildNewRa(any(), notNull());
verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks(
any(), any());
@@ -858,6 +867,8 @@ public class TetheringTest {
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ // TODO: add interfaceParams to compare in verify.
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
@@ -874,6 +885,7 @@ public class TetheringTest {
any(), any());
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
@@ -891,6 +903,7 @@ public class TetheringTest {
verify(mNetd, times(1)).ipfwdAddInterfaceForward(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
sendIPv6TetherUpdates(upstreamState);
+ verify(mDadProxy, times(1)).setUpstreamIface(notNull());
verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 9495fb5fdc77..ff794691d2b4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -730,7 +730,8 @@ public class AccessibilityWindowManager {
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
- case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
+ case WindowManager.LayoutParams.TYPE_SCREENSHOT:
+ case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index b7fed87d570d..958c15c8d432 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -50,5 +50,10 @@ public abstract class BatteryStatsInternal {
* Informs battery stats of binder stats for the given work source UID.
*/
public abstract void noteBinderCallStats(int workSourceUid, long incrementalBinderCallCount,
- Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids);
+ Collection<BinderCallsStats.CallStat> callStats);
+
+ /**
+ * Informs battery stats of native thread IDs of threads taking incoming binder calls.
+ */
+ public abstract void noteBinderThreadNativeIds(int[] binderThreadNativeTids);
}
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index c9513592ea79..66ac889ff2ca 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -49,6 +49,7 @@ import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
public class BinderCallsStatsService extends Binder {
@@ -273,7 +274,19 @@ public class BinderCallsStatsService extends Binder {
BatteryStatsInternal batteryStatsInternal = getLocalService(
BatteryStatsInternal.class);
- mBinderCallsStats.setCallStatsObserver(batteryStatsInternal::noteBinderCallStats);
+ mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
+ @Override
+ public void noteCallStats(int workSourceUid, long incrementalCallCount,
+ Collection<BinderCallsStats.CallStat> callStats) {
+ batteryStatsInternal.noteBinderCallStats(workSourceUid,
+ incrementalCallCount, callStats);
+ }
+
+ @Override
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
+ }
+ });
// It needs to be called before mService.systemReady to make sure the observer is
// initialized before installing it.
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index e342c1fcf114..6d774869b391 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4641,6 +4641,11 @@ class StorageManagerService extends IStorageManager.Stub
// make sure the OBB dir for the application is setup correctly, if it exists.
File[] packageObbDirs = userEnv.buildExternalStorageAppObbDirs(packageName);
for (File packageObbDir : packageObbDirs) {
+ if (packageObbDir.getPath().startsWith(
+ Environment.getDataPreloadsMediaDirectory().getPath())) {
+ Slog.i(TAG, "Skipping app data preparation for " + packageObbDir);
+ continue;
+ }
try {
mVold.fixupAppDir(packageObbDir.getCanonicalPath() + "/", uid);
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index bcb7bfacfaf3..0135b9d2f8ab 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -72,7 +72,6 @@ import com.android.internal.app.DisableCarModeActivity;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.DumpUtils;
-import com.android.server.SystemService.TargetUser;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
@@ -327,8 +326,16 @@ final class UiModeManagerService extends SystemService {
@Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
mCurrentUser = to.getUserIdentifier();
+ if (mNightMode == MODE_NIGHT_AUTO) persistComputedNightMode(from.getUserIdentifier());
getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
verifySetupWizardCompleted();
+ synchronized (mLock) {
+ // only update if the value is actually changed
+ if (updateNightModeFromSettingsLocked(getContext(), getContext().getResources(),
+ to.getUserIdentifier())) {
+ updateLocked(0, 0);
+ }
+ }
}
@Override
@@ -356,11 +363,10 @@ final class UiModeManagerService extends SystemService {
new IntentFilter(Intent.ACTION_DOCK_EVENT));
IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(mBatteryReceiver, batteryFilter);
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(mSettingsRestored,
new IntentFilter(Intent.ACTION_SETTING_RESTORED));
- context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
+ context.registerReceiver(mOnShutdown,
+ new IntentFilter(Intent.ACTION_SHUTDOWN));
updateConfigurationLocked();
applyConfigurationExternallyLocked();
}
@@ -407,6 +413,21 @@ final class UiModeManagerService extends SystemService {
publishLocalService(UiModeManagerInternal.class, mLocalService);
}
+ private final BroadcastReceiver mOnShutdown = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mNightMode == MODE_NIGHT_AUTO) {
+ persistComputedNightMode(mCurrentUser);
+ }
+ }
+ };
+
+ private void persistComputedNightMode(int userId) {
+ Secure.putIntForUser(getContext().getContentResolver(),
+ Secure.UI_NIGHT_MODE_LAST_COMPUTED, mComputedNightMode ? 1 : 0,
+ userId);
+ }
+
private final BroadcastReceiver mSettingsRestored = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -508,6 +529,10 @@ final class UiModeManagerService extends SystemService {
Secure.getLongForUser(context.getContentResolver(),
Secure.DARK_THEME_CUSTOM_END_TIME,
DEFAULT_CUSTOM_NIGHT_END_TIME.toNanoOfDay() / 1000L, userId) * 1000);
+ if (mNightMode == MODE_NIGHT_AUTO) {
+ mComputedNightMode = Secure.getIntForUser(context.getContentResolver(),
+ Secure.UI_NIGHT_MODE_LAST_COMPUTED, 0, userId) != 0;
+ }
}
return oldNightMode != mNightMode;
@@ -1630,18 +1655,4 @@ final class UiModeManagerService extends SystemService {
}
}
}
-
- private final class UserSwitchedReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- final int currentId = intent.getIntExtra(
- Intent.EXTRA_USER_HANDLE, USER_SYSTEM);
- // only update if the value is actually changed
- if (updateNightModeFromSettingsLocked(context, context.getResources(), currentId)) {
- updateLocked(0, 0);
- }
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bfe04e628f81..c0f6011a45cd 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -482,13 +482,14 @@ public final class ActiveServices {
String callingPackage, @Nullable String callingFeatureId, final int userId)
throws TransactionTooLargeException {
return startServiceLocked(caller, service, resolvedType, callingPid, callingUid, fgRequired,
- hideFgNotification, callingPackage, callingFeatureId, userId, false);
+ hideFgNotification, callingPackage, callingFeatureId, userId, false, null);
}
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, boolean hideFgNotification,
String callingPackage, @Nullable String callingFeatureId, final int userId,
- boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
+ boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken)
+ throws TransactionTooLargeException {
if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
@@ -733,7 +734,7 @@ public final class ActiveServices {
}
}
if (allowBackgroundActivityStarts) {
- r.allowBgActivityStartsOnServiceStart();
+ r.allowBgActivityStartsOnServiceStart(backgroundActivityStartsToken);
}
ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
return cmp;
@@ -2609,12 +2610,12 @@ public final class ActiveServices {
private int getAllowMode(Intent service, @Nullable String callingPackage) {
if (callingPackage == null || service.getComponent() == null) {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
}
if (callingPackage.equals(service.getComponent().getPackageName())) {
- return ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
} else {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2de3e525d2da..bd7d3de9d200 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16306,7 +16306,8 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
res = mServices.startServiceLocked(null, service,
resolvedType, -1, uid, fgRequired, false, callingPackage,
- callingFeatureId, userId, allowBackgroundActivityStarts);
+ callingFeatureId, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 808a6993af1a..76125aabc978 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -240,14 +240,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub
@Override
public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
- Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
+ Collection<BinderCallsStats.CallStat> callStats) {
synchronized (BatteryStatsService.this.mLock) {
mHandler.sendMessage(PooledLambda.obtainMessage(
- mStats::noteBinderCallStats, workSourceUid, incrementatCallCount,
- callStats, binderThreadNativeTids,
+ mStats::noteBinderCallStats, workSourceUid, incrementatCallCount, callStats,
SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()));
}
}
+
+ @Override
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ synchronized (BatteryStatsService.this.mLock) {
+ mStats.noteBinderThreadNativeIds(binderThreadNativeTids);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 93105daa6c5d..57f811215e50 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1686,7 +1686,7 @@ public final class BroadcastQueue {
// that request - we don't want the token to be swept from under our feet...
mHandler.removeCallbacksAndMessages(msgToken);
// ...then add the token
- proc.addAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken);
+ proc.addOrUpdateAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken);
}
final void setBroadcastTimeoutLocked(long timeoutTime) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f1e12c55df18..2dced8d704bb 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -77,6 +77,7 @@ import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -1338,13 +1339,15 @@ class ProcessRecord implements WindowProcessListener {
* {@param originatingToken} if you have one such originating token, this is useful for tracing
* back the grant in the case of the notification token.
*/
- void addAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) {
- if (entity == null) return;
- mWindowProcessController.addAllowBackgroundActivityStartsToken(entity, originatingToken);
+ void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
+ @Nullable IBinder originatingToken) {
+ Objects.requireNonNull(entity);
+ mWindowProcessController.addOrUpdateAllowBackgroundActivityStartsToken(entity,
+ originatingToken);
}
void removeAllowBackgroundActivityStartsToken(Binder entity) {
- if (entity == null) return;
+ Objects.requireNonNull(entity);
mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity);
}
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 55e0f2ea5212..a7d8ca496f75 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -22,6 +22,7 @@ import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -139,6 +140,12 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
// used to clean up the state of mIsAllowedBgActivityStartsByStart after a timeout
private Runnable mCleanUpAllowBgActivityStartsByStartCallback;
private ProcessRecord mAppForAllowingBgActivityStartsByStart;
+ // These are the originating tokens that currently allow bg activity starts by service start.
+ // This is used to trace back the grant when starting activities. We only pass such token to the
+ // ProcessRecord if it's the *only* cause for bg activity starts exemption, otherwise we pass
+ // null.
+ @GuardedBy("ams")
+ private List<IBinder> mBgActivityStartsByStartOriginatingTokens = new ArrayList<>();
// allow while-in-use permissions in foreground service or not.
// while-in-use permissions in FGS started from background might be restricted.
@@ -588,7 +595,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
? _proc : null;
if (mIsAllowedBgActivityStartsByStart
|| mIsAllowedBgActivityStartsByBinding) {
- _proc.addAllowBackgroundActivityStartsToken(this, null);
+ _proc.addOrUpdateAllowBackgroundActivityStartsToken(this,
+ getExclusiveOriginatingToken());
} else {
_proc.removeAllowBackgroundActivityStartsToken(this);
}
@@ -679,10 +687,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
}
void setAllowedBgActivityStartsByBinding(boolean newValue) {
- if (mIsAllowedBgActivityStartsByBinding != newValue) {
- mIsAllowedBgActivityStartsByBinding = newValue;
- updateParentProcessBgActivityStartsToken();
- }
+ mIsAllowedBgActivityStartsByBinding = newValue;
+ updateParentProcessBgActivityStartsToken();
}
/**
@@ -691,7 +697,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
* timeout. Note that the ability for starting background activities persists for the process
* even if the service is subsequently stopped.
*/
- void allowBgActivityStartsOnServiceStart() {
+ void allowBgActivityStartsOnServiceStart(@Nullable IBinder originatingToken) {
+ mBgActivityStartsByStartOriginatingTokens.add(originatingToken);
setAllowedBgActivityStartsByStart(true);
if (app != null) {
mAppForAllowingBgActivityStartsByStart = app;
@@ -701,32 +708,49 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
if (mCleanUpAllowBgActivityStartsByStartCallback == null) {
mCleanUpAllowBgActivityStartsByStartCallback = () -> {
synchronized (ams) {
- if (app == mAppForAllowingBgActivityStartsByStart) {
- // The process we allowed is still running the service. We remove
- // the ability by start, but it may still be allowed via bound connections.
- setAllowedBgActivityStartsByStart(false);
- } else if (mAppForAllowingBgActivityStartsByStart != null) {
- // The process we allowed is not running the service. It therefore can't be
- // bound so we can unconditionally remove the ability.
- mAppForAllowingBgActivityStartsByStart
- .removeAllowBackgroundActivityStartsToken(ServiceRecord.this);
+ mBgActivityStartsByStartOriginatingTokens.remove(0);
+ if (!mBgActivityStartsByStartOriginatingTokens.isEmpty()) {
+ // There are other callbacks in the queue, let's just update the originating
+ // token
+ if (mIsAllowedBgActivityStartsByStart) {
+ mAppForAllowingBgActivityStartsByStart
+ .addOrUpdateAllowBackgroundActivityStartsToken(
+ this, getExclusiveOriginatingToken());
+ } else {
+ Slog.wtf(TAG,
+ "Service callback to revoke bg activity starts by service "
+ + "start triggered but "
+ + "mIsAllowedBgActivityStartsByStart = false. This "
+ + "should never happen.");
+ }
+ } else {
+ // Last callback on the queue
+ if (app == mAppForAllowingBgActivityStartsByStart) {
+ // The process we allowed is still running the service. We remove
+ // the ability by start, but it may still be allowed via bound
+ // connections.
+ setAllowedBgActivityStartsByStart(false);
+ } else if (mAppForAllowingBgActivityStartsByStart != null) {
+ // The process we allowed is not running the service. It therefore can't
+ // be bound so we can unconditionally remove the ability.
+ mAppForAllowingBgActivityStartsByStart
+ .removeAllowBackgroundActivityStartsToken(ServiceRecord.this);
+ }
+ mAppForAllowingBgActivityStartsByStart = null;
}
- mAppForAllowingBgActivityStartsByStart = null;
}
};
}
- // if there's a request pending from the past, drop it before scheduling a new one
- ams.mHandler.removeCallbacks(mCleanUpAllowBgActivityStartsByStartCallback);
+ // Existing callbacks will only update the originating token, only when the last callback is
+ // executed is the grant revoked.
ams.mHandler.postDelayed(mCleanUpAllowBgActivityStartsByStartCallback,
ams.mConstants.SERVICE_BG_ACTIVITY_START_TIMEOUT);
}
private void setAllowedBgActivityStartsByStart(boolean newValue) {
- if (mIsAllowedBgActivityStartsByStart != newValue) {
- mIsAllowedBgActivityStartsByStart = newValue;
- updateParentProcessBgActivityStartsToken();
- }
+ mIsAllowedBgActivityStartsByStart = newValue;
+ updateParentProcessBgActivityStartsToken();
}
/**
@@ -736,8 +760,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
* {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord
* should be contributing as a token in parent ProcessRecord.
*
- * @see com.android.server.am.ProcessRecord#addAllowBackgroundActivityStartsToken(Binder,
- * IBinder)
+ * @see com.android.server.am.ProcessRecord#addOrUpdateAllowBackgroundActivityStartsToken(
+ * Binder, IBinder)
* @see com.android.server.am.ProcessRecord#removeAllowBackgroundActivityStartsToken(Binder)
*/
private void updateParentProcessBgActivityStartsToken() {
@@ -747,12 +771,37 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) {
// if the token is already there it's safe to "re-add it" - we're dealing with
// a set of Binder objects
- app.addAllowBackgroundActivityStartsToken(this, null);
+ app.addOrUpdateAllowBackgroundActivityStartsToken(this, getExclusiveOriginatingToken());
} else {
app.removeAllowBackgroundActivityStartsToken(this);
}
}
+ /**
+ * Returns the originating token if that's the only reason background activity starts are
+ * allowed. In order for that to happen the service has to be allowed only due to starts, since
+ * bindings are not associated with originating tokens, and all the start tokens have to be the
+ * same and there can't be any null originating token in the queue.
+ *
+ * Originating tokens are optional, so the caller could provide null when it allows bg activity
+ * starts.
+ */
+ @Nullable
+ private IBinder getExclusiveOriginatingToken() {
+ if (mIsAllowedBgActivityStartsByBinding
+ || mBgActivityStartsByStartOriginatingTokens.isEmpty()) {
+ return null;
+ }
+ IBinder firstToken = mBgActivityStartsByStartOriginatingTokens.get(0);
+ for (int i = 1, n = mBgActivityStartsByStartOriginatingTokens.size(); i < n; i++) {
+ IBinder token = mBgActivityStartsByStartOriginatingTokens.get(i);
+ if (token != firstToken) {
+ return null;
+ }
+ }
+ return firstToken;
+ }
+
@GuardedBy("ams")
void updateKeepWarmLocked() {
mKeepWarming = ams.mConstants.KEEP_WARMING_SERVICES.contains(name)
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3dfbcc71dd3c..eb60573e6f17 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -23,11 +23,10 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1912,12 +1911,11 @@ class UserController implements Handler.Callback {
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
- } else if (allowMode == ALLOW_NON_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
- } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE_OR_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
+ || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup;
@@ -1944,15 +1942,12 @@ class UserController implements Handler.Callback {
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
- if (allowMode == ALLOW_NON_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL
- || isSameProfileGroup) {
+ if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
if (isSameProfileGroup
- && (allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
- || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL)) {
+ && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_PROFILES);
}
@@ -1979,8 +1974,7 @@ class UserController implements Handler.Callback {
private boolean canInteractWithAcrossProfilesPermission(
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
String callingPackage) {
- if (allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
- && allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
+ if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
return false;
}
if (!isSameProfileGroup) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 6099e52e54e9..668713f0fee7 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,7 +19,6 @@ package com.android.server.appop;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
@@ -37,7 +36,6 @@ import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
-import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
@@ -131,7 +129,6 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -165,7 +162,6 @@ import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
-import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2203,11 +2199,8 @@ public class AppOpsService extends IAppOpsService.Stub {
+ " by uid " + Binder.getCallingUid());
}
- int userId = UserHandle.getUserId(uid);
-
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
code = AppOpsManager.opToSwitch(code);
if (permissionPolicyCallback == null) {
@@ -2252,11 +2245,6 @@ public class AppOpsService extends IAppOpsService.Stub {
scheduleWriteLocked();
}
uidState.evalForegroundOps(mOpModeWatchers);
-
- if (code == OP_INTERACT_ACROSS_PROFILES) {
- // Invalidate package info cache as the visibility of packages might have changed
- PackageManager.invalidatePackageInfoCache();
- }
}
notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
@@ -2462,12 +2450,8 @@ public class AppOpsService extends IAppOpsService.Stub {
private void setMode(int code, int uid, @NonNull String packageName, int mode,
@Nullable IAppOpsCallback permissionPolicyCallback) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -2729,9 +2713,6 @@ public class AppOpsService extends IAppOpsService.Stub {
if (changed) {
scheduleFastWriteLocked();
-
- // Invalidate package info cache as the visibility of packages might have changed
- PackageManager.invalidatePackageInfoCache();
}
}
if (callbacks != null) {
@@ -2890,11 +2871,8 @@ public class AppOpsService extends IAppOpsService.Stub {
private int checkOperationImpl(int code, int uid, String packageName,
boolean raw) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3013,15 +2991,10 @@ public class AppOpsService extends IAppOpsService.Stub {
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
- int proxiedUserId = UserHandle.getUserId(proxiedUid);
- int proxyUserId = UserHandle.getUserId(proxyUid);
-
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
- verifyIncomingUser(proxiedUserId);
- verifyIncomingUser(proxyUserId);
- verifyIncomingPackage(proxiedPackageName, proxiedUserId);
- verifyIncomingPackage(proxyPackageName, proxyUserId);
+ verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+ verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
if (resolveProxyPackageName == null) {
@@ -3071,12 +3044,9 @@ public class AppOpsService extends IAppOpsService.Stub {
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3453,12 +3423,9 @@ public class AppOpsService extends IAppOpsService.Stub {
public int startOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3550,12 +3517,9 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3784,33 +3748,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
- private void verifyIncomingUser(@UserIdInt int userId) {
- int callingUid = Binder.getCallingUid();
- int callingUserId = UserHandle.getUserId(callingUid);
- int callingPid = Binder.getCallingPid();
-
- if (callingUserId != userId) {
- // Prevent endless loop between when checking appops inside of handleIncomingUser
- if (Binder.getCallingPid() == ActivityManagerService.MY_PID) {
- return;
- }
- long token = Binder.clearCallingIdentity();
- try {
- try {
- LocalServices.getService(ActivityManagerInternal.class).handleIncomingUser(
- callingPid, callingUid, userId, /* allowAll */ false,
- ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL, "appop operation", null);
- } catch (Exception e) {
- EventLog.writeEvent(0x534e4554, "153996875", "appop", userId);
-
- throw e;
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
-
private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
@@ -5890,11 +5827,8 @@ public class AppOpsService extends IAppOpsService.Stub {
return false;
}
}
- int userId = UserHandle.getUserId(uid);
-
verifyIncomingOp(code);
- verifyIncomingUser(userId);
- verifyIncomingPackage(packageName, userId);
+ verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
final String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index a3e1b7a7e5c5..84de25c06ebf 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -7,9 +7,6 @@
"name": "CtsAppOps2TestCases"
},
{
- "name": "CtsAppOpHostTestCases"
- },
- {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6110759b5a9e..f1561cab8fb4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6735,14 +6735,17 @@ public class AudioService extends IAudioService.Stub
if (msg.obj == null) {
break;
}
- // If the app corresponding to this mode death handler object is not
- // capturing or playing audio anymore after 3 seconds, remove it
- // from the stack. Otherwise, check again in 3 seconds.
+ // If no other app is currently owning the audio mode and
+ // the app corresponding to this mode death handler object is still in the
+ // mode owner stack but not capturing or playing audio after 3 seconds,
+ // remove it from the stack.
+ // Otherwise, check again in 3 seconds.
SetModeDeathHandler h = (SetModeDeathHandler) msg.obj;
if (mSetModeDeathHandlers.indexOf(h) < 0) {
break;
}
- if (mRecordMonitor.isRecordingActiveForUid(h.getUid())
+ if (getModeOwnerUid() != h.getUid()
+ || mRecordMonitor.isRecordingActiveForUid(h.getUid())
|| mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())) {
sendMsg(mAudioHandler,
MSG_CHECK_MODE_FOR_UID,
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index ded0f9a3dca7..8de31d999b53 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -450,6 +450,7 @@ public class BtHelper {
}
@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ // @GuardedBy("BtHelper.this")
private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 0b4f31d365d3..28bd97e4843c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -117,14 +117,15 @@ public class HdmiCecMessageValidator {
// TODO: Validate more than length for the following messages.
// Messages for the One Touch Record.
- FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
addValidationInfo(Constants.MESSAGE_RECORD_ON,
new VariableLengthValidator(1, 8), DEST_DIRECT);
- addValidationInfo(Constants.MESSAGE_RECORD_STATUS, oneByteValidator, DEST_DIRECT);
+ addValidationInfo(Constants.MESSAGE_RECORD_STATUS,
+ new RecordStatusInfoValidator(), DEST_DIRECT);
// TODO: Handle messages for the Timer Programming.
// Messages for the System Information.
+ FixedLengthValidator oneByteValidator = new FixedLengthValidator(1);
addValidationInfo(Constants.MESSAGE_CEC_VERSION, oneByteValidator, DEST_DIRECT);
addValidationInfo(Constants.MESSAGE_SET_MENU_LANGUAGE,
new FixedLengthValidator(3), DEST_BROADCAST);
@@ -339,4 +340,23 @@ public class HdmiCecMessageValidator {
isValidPhysicalAddress(params, 0) && isValidPhysicalAddress(params, 2));
}
}
+
+ /**
+ * Check if the given record status message parameter is valid.
+ * A valid parameter should lie within the range description of Record Status Info defined in
+ * CEC 1.4 Specification : Operand Descriptions (Section 17)
+ */
+ private class RecordStatusInfoValidator implements ParameterValidator {
+ @Override
+ public int isValid(byte[] params) {
+ if (params.length < 1) {
+ return ERROR_PARAMETER_SHORT;
+ }
+ return toErrorCode(isWithinRange(params[0], 0x01, 0x07)
+ || isWithinRange(params[0], 0x09, 0x0E)
+ || isWithinRange(params[0], 0x10, 0x17)
+ || isWithinRange(params[0], 0x1A, 0x1B)
+ || params[0] == 0x1F);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 68961d9c94d8..7e53e6f3e2c3 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2616,7 +2616,6 @@ public class LockSettingsService extends ILockSettings.Stub {
final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(
getGateKeeperService(), credentialHash, credential, userId);
- onAuthTokenKnownForUser(userId, auth);
if (auth == null) {
Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
return null;
@@ -2639,6 +2638,7 @@ public class LockSettingsService extends ILockSettings.Stub {
}
fixateNewestUserKeyAuth(userId);
setSyntheticPasswordHandleLocked(handle, userId);
+ onAuthTokenKnownForUser(userId, auth);
return auth;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7401403de127..1fd7a73f1174 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -309,6 +309,7 @@ import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -1528,10 +1529,10 @@ public class NotificationManagerService extends SystemService {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
!queryRestart, changeUserId, reason, null);
}
- } else if (hideNotifications) {
- hideNotificationsForPackages(pkgList);
- } else if (unhideNotifications) {
- unhideNotificationsForPackages(pkgList);
+ } else if (hideNotifications && uidList != null && (uidList.length > 0)) {
+ hideNotificationsForPackages(pkgList, uidList);
+ } else if (unhideNotifications && uidList != null && (uidList.length > 0)) {
+ unhideNotificationsForPackages(pkgList, uidList);
}
}
@@ -2076,6 +2077,68 @@ public class NotificationManagerService extends SystemService {
mMsgPkgsAllowedAsConvos = Set.of(getStringArrayResource(
com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos));
mStatsManager = statsManager;
+
+ // register for various Intents.
+ // If this is called within a test, make sure to unregister the intent receivers by
+ // calling onDestroy()
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
+ filter.addAction(Intent.ACTION_USER_STOPPED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
+
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ pkgFilter.addDataScheme("package");
+ getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
+ null);
+
+ IntentFilter suspendedPkgFilter = new IntentFilter();
+ suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+ suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
+ getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
+ suspendedPkgFilter, null, null);
+
+ IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
+ null);
+
+ IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
+ timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
+ getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
+
+ IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
+ getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
+
+ IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
+ getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
+ }
+
+ /**
+ * Cleanup broadcast receivers change listeners.
+ */
+ public void onDestroy() {
+ getContext().unregisterReceiver(mIntentReceiver);
+ getContext().unregisterReceiver(mPackageIntentReceiver);
+ getContext().unregisterReceiver(mNotificationTimeoutReceiver);
+ getContext().unregisterReceiver(mRestoreReceiver);
+ getContext().unregisterReceiver(mLocaleChangeReceiver);
+
+ if (mDeviceConfigChangedListener != null) {
+ DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener);
+ }
}
protected String[] getStringArrayResource(int key) {
@@ -2126,51 +2189,6 @@ public class NotificationManagerService extends SystemService {
Context.STATS_MANAGER),
getContext().getSystemService(TelephonyManager.class));
- // register for various Intents
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
- filter.addAction(Intent.ACTION_USER_PRESENT);
- filter.addAction(Intent.ACTION_USER_STOPPED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_USER_ADDED);
- filter.addAction(Intent.ACTION_USER_REMOVED);
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
-
- IntentFilter pkgFilter = new IntentFilter();
- pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
- pkgFilter.addDataScheme("package");
- getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
- null);
-
- IntentFilter suspendedPkgFilter = new IntentFilter();
- suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
- suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
- suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
- getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
- suspendedPkgFilter, null, null);
-
- IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
- null);
-
- IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
- timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
- getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
-
- IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
- getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
-
- IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
- getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
-
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
publishLocalService(NotificationManagerInternal.class, mInternalService);
@@ -2193,12 +2211,6 @@ public class NotificationManagerService extends SystemService {
mDeviceConfigChangedListener);
}
- void unregisterDeviceConfigChange() {
- if (mDeviceConfigChangedListener != null) {
- DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener);
- }
- }
-
private void registerNotificationPreferencesPullers() {
mPullAtomCallback = new StatsPullAtomCallbackImpl();
mStatsManager.setPullAtomCallback(
@@ -8339,15 +8351,16 @@ public class NotificationManagerService extends SystemService {
return -1;
}
- @VisibleForTesting
- protected void hideNotificationsForPackages(String[] pkgs) {
+ private void hideNotificationsForPackages(@NonNull String[] pkgs, @NonNull int[] uidList) {
synchronized (mNotificationLock) {
+ Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
List<String> pkgList = Arrays.asList(pkgs);
List<NotificationRecord> changedNotifications = new ArrayList<>();
int numNotifications = mNotificationList.size();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
- if (pkgList.contains(rec.getSbn().getPackageName())) {
+ if (pkgList.contains(rec.getSbn().getPackageName())
+ && uidSet.contains(rec.getUid())) {
rec.setHidden(true);
changedNotifications.add(rec);
}
@@ -8357,15 +8370,17 @@ public class NotificationManagerService extends SystemService {
}
}
- @VisibleForTesting
- protected void unhideNotificationsForPackages(String[] pkgs) {
+ private void unhideNotificationsForPackages(@NonNull String[] pkgs,
+ @NonNull int[] uidList) {
synchronized (mNotificationLock) {
+ Set<Integer> uidSet = Arrays.stream(uidList).boxed().collect(Collectors.toSet());
List<String> pkgList = Arrays.asList(pkgs);
List<NotificationRecord> changedNotifications = new ArrayList<>();
int numNotifications = mNotificationList.size();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
- if (pkgList.contains(rec.getSbn().getPackageName())) {
+ if (pkgList.contains(rec.getSbn().getPackageName())
+ && uidSet.contains(rec.getUid())) {
rec.setHidden(false);
changedNotifications.add(rec);
}
@@ -9939,38 +9954,6 @@ public class NotificationManagerService extends SystemService {
return CollectionUtils.firstOrNull(allowedComponents);
}
- @VisibleForTesting
- protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
- checkCallerIsSystemOrShell();
- // only use for testing: mimic receive broadcast that package is (un)suspended
- // but does not actually (un)suspend the package
- final Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
- new String[]{pkg});
-
- final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
- : Intent.ACTION_PACKAGES_UNSUSPENDED;
- final Intent intent = new Intent(action);
- intent.putExtras(extras);
-
- mPackageIntentReceiver.onReceive(getContext(), intent);
- }
-
- @VisibleForTesting
- protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
- checkCallerIsSystemOrShell();
- // only use for testing: mimic receive broadcast that package is (un)distracting
- // but does not actually register that info with packagemanager
- final Bundle extras = new Bundle();
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
- extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
-
- final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
- intent.putExtras(extras);
-
- mPackageIntentReceiver.onReceive(getContext(), intent);
- }
-
/**
* Wrapper for a StatusBarNotification object that allows transfer across a oneway
* binder without sending large amounts of data over a oneway transaction.
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index da7864ba32c4..927dc25ac6ce 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -66,8 +66,6 @@ public class NotificationShellCmd extends ShellCommand {
+ " set_dnd [on|none (same as on)|priority|alarms|all|off (same as all)]"
+ " allow_dnd PACKAGE [user_id (current user if not specified)]\n"
+ " disallow_dnd PACKAGE [user_id (current user if not specified)]\n"
- + " suspend_package PACKAGE\n"
- + " unsuspend_package PACKAGE\n"
+ " reset_assistant_user_set [user_id (current user if not specified)]\n"
+ " get_approved_assistant [user_id (current user if not specified)]\n"
+ " post [--help | flags] TAG TEXT\n"
@@ -258,25 +256,6 @@ public class NotificationShellCmd extends ShellCommand {
mBinderService.setNotificationAssistantAccessGrantedForUser(cn, userId, false);
}
break;
- case "suspend_package": {
- // only use for testing
- mDirectService.simulatePackageSuspendBroadcast(true, getNextArgRequired());
- }
- break;
- case "unsuspend_package": {
- // only use for testing
- mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
- }
- break;
- case "distract_package": {
- // only use for testing
- // Flag values are in
- // {@link android.content.pm.PackageManager.DistractionRestriction}.
- mDirectService.simulatePackageDistractionBroadcast(
- Integer.parseInt(getNextArgRequired()),
- getNextArgRequired().split(","));
- break;
- }
case "reset_assistant_user_set": {
int userId = ActivityManager.getCurrentUser();
if (peekNextArg() != null) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f52db5fb5f2f..31ee59717dba 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -618,6 +618,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
+ && !isCalledBySystemOrShell(callingUid)
+ && (mPm.getFlagsForUid(callingUid) & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ throw new SecurityException(
+ "Only system apps could use the PackageManager.INSTALL_INSTANT_APP flag.");
+ }
+
if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
if (mBypassNextStagedInstallerCheck) {
mBypassNextStagedInstallerCheck = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 697c31a78ec7..f94de227f3e9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1849,7 +1849,6 @@ public class PackageManagerService extends IPackageManager.Stub
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mLock) {
removeMessages(WRITE_PACKAGE_LIST);
- mPermissionManager.writeStateToPackageSettingsTEMP();
mSettings.writePackageListLPr(msg.arg1);
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
@@ -2686,7 +2685,8 @@ public class PackageManagerService extends IPackageManager.Stub
(i, pm) ->
new Settings(Environment.getDataDirectory(),
i.getPermissionManagerServiceInternal().getPermissionSettings(),
- RuntimePermissionsPersistence.createInstance(), lock),
+ RuntimePermissionsPersistence.createInstance(),
+ i.getPermissionManagerServiceInternal(), lock),
new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
@@ -4486,8 +4486,8 @@ public class PackageManagerService extends IPackageManager.Stub
AndroidPackage p = ps.pkg;
if (p != null) {
// Compute GIDs only if requested
- final int[] gids = (flags & PackageManager.GET_GIDS) == 0
- ? EMPTY_INT_ARRAY : mPermissionManager.getPackageGids(ps.name, userId);
+ final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
+ : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
// Compute granted permissions only if package has requested permissions
final Set<String> permissions = ArrayUtils.isEmpty(p.getRequestedPermissions())
? Collections.emptySet()
@@ -4962,13 +4962,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
// TODO: Shouldn't this be checking for package installed state for userId and
// return null?
- return mPermissionManager.getPackageGids(packageName, userId);
+ return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
if ((flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null && ps.isMatch(flags)
&& !shouldFilterApplicationLocked(ps, callingUid, userId)) {
- return mPermissionManager.getPackageGids(packageName, userId);
+ return mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.appId));
}
}
}
@@ -18983,7 +18983,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
if ((deletedPs.sharedUser == null || deletedPs.sharedUser.packages.size() == 0)
&& !isUpdatedSystemApp(deletedPs)) {
- mPermissionManager.removePermissionsStateTEMP(removedAppId);
+ mPermissionManager.removeAppIdStateTEMP(removedAppId);
}
mPermissionManager.updatePermissions(deletedPs.name, null);
if (deletedPs.sharedUser != null) {
@@ -21242,7 +21242,8 @@ public class PackageManagerService extends IPackageManager.Stub
// Prior to enabling the package, we need to decompress the APK(s) to the
// data partition and then replace the version on the system partition.
final AndroidPackage deletedPkg = pkgSetting.pkg;
- final boolean isSystemStub = deletedPkg.isStub()
+ final boolean isSystemStub = (deletedPkg != null)
+ && deletedPkg.isStub()
&& deletedPkg.isSystem();
if (isSystemStub
&& (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
@@ -21854,8 +21855,6 @@ public class PackageManagerService extends IPackageManager.Stub
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- mPermissionManager.writeStateToPackageSettingsTEMP();
-
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
boolean checkin = false;
@@ -23734,7 +23733,6 @@ public class PackageManagerService extends IPackageManager.Stub
mDirtyUsers.remove(userId);
mUserNeedsBadging.delete(userId);
mPermissionManager.onUserRemoved(userId);
- mPermissionManager.writeStateToPackageSettingsTEMP();
mSettings.removeUserLPw(userId);
mPendingBroadcasts.remove(userId);
mInstantAppRegistry.onUserRemovedLPw(userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d77683e8ba61..afbf7d3a35af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2323,7 +2323,8 @@ class PackageManagerShellCommand extends ShellCommand {
private boolean isVendorApp(String pkg) {
try {
- final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ final PackageInfo info = mInterface.getPackageInfo(
+ pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
return info != null && info.applicationInfo.isVendor();
} catch (RemoteException e) {
return false;
@@ -2332,7 +2333,8 @@ class PackageManagerShellCommand extends ShellCommand {
private boolean isProductApp(String pkg) {
try {
- final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ final PackageInfo info = mInterface.getPackageInfo(
+ pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
return info != null && info.applicationInfo.isProduct();
} catch (RemoteException e) {
return false;
@@ -2341,7 +2343,8 @@ class PackageManagerShellCommand extends ShellCommand {
private boolean isSystemExtApp(String pkg) {
try {
- final PackageInfo info = mInterface.getPackageInfo(pkg, 0, UserHandle.USER_SYSTEM);
+ final PackageInfo info = mInterface.getPackageInfo(
+ pkg, PackageManager.MATCH_ANY_USER, UserHandle.USER_SYSTEM);
return info != null && info.applicationInfo.isSystemExt();
} catch (RemoteException e) {
return false;
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 276f88082df0..855a5ff524fd 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -28,7 +28,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
-import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.AppIdPermissionState;
import com.android.server.pm.pkg.PackageStateUnserialized;
import java.io.File;
@@ -215,7 +215,7 @@ public class PackageSetting extends PackageSettingBase {
}
@Override
- public PermissionsState getPermissionsState() {
+ public AppIdPermissionState getPermissionsState() {
return (sharedUser != null)
? sharedUser.getPermissionsState()
: super.getPermissionsState();
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 3e2ab05e83ec..c1258b1efd48 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -19,23 +19,23 @@ package com.android.server.pm;
import android.content.pm.ApplicationInfo;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.permission.PermissionsState;
+import com.android.server.pm.permission.AppIdPermissionState;
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public abstract class SettingBase {
int pkgFlags;
int pkgPrivateFlags;
- protected final PermissionsState mPermissionsState;
+ protected final AppIdPermissionState mPermissionsState;
SettingBase(int pkgFlags, int pkgPrivateFlags) {
setFlags(pkgFlags);
setPrivateFlags(pkgPrivateFlags);
- mPermissionsState = new PermissionsState();
+ mPermissionsState = new AppIdPermissionState();
}
SettingBase(SettingBase orig) {
- mPermissionsState = new PermissionsState();
+ mPermissionsState = new AppIdPermissionState();
doCopy(orig);
}
@@ -49,7 +49,7 @@ public abstract class SettingBase {
mPermissionsState.copyFrom(orig.mPermissionsState);
}
- public PermissionsState getPermissionsState() {
+ public AppIdPermissionState getPermissionsState() {
return mPermissionsState;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 965430727d3c..bae36b2ad353 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -79,6 +79,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.IntArray;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Pair;
@@ -106,10 +107,11 @@ import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.permission.AppIdPermissionState;
+import com.android.server.pm.permission.AppIdPermissionState.PermissionState;
import com.android.server.pm.permission.BasePermission;
+import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.PermissionSettings;
-import com.android.server.pm.permission.PermissionsState;
-import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.utils.TimingsTraceAndSlog;
import libcore.io.IoUtils;
@@ -416,9 +418,12 @@ public final class Settings {
private final File mSystemDir;
public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
+
/** Settings and other information about permissions */
final PermissionSettings mPermissions;
+ private final LegacyPermissionDataProvider mPermissionDataProvider;
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public Settings(Map<String, PackageSetting> pkgSettings) {
mLock = new Object();
@@ -426,6 +431,7 @@ public final class Settings {
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
+ mPermissionDataProvider = null;
mSettingsFilename = null;
mBackupSettingsFilename = null;
mPackageListFilename = null;
@@ -434,12 +440,14 @@ public final class Settings {
mKernelMappingFilename = null;
}
- Settings(File dataDir, PermissionSettings permission,
- RuntimePermissionsPersistence runtimePermissionsPersistence, Object lock) {
+ Settings(File dataDir, PermissionSettings permissionSettings,
+ RuntimePermissionsPersistence runtimePermissionsPersistence,
+ LegacyPermissionDataProvider permissionDataProvider, Object lock) {
mLock = lock;
- mPermissions = permission;
+ mPermissions = permissionSettings;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
- runtimePermissionsPersistence, mLock);
+ runtimePermissionsPersistence);
+ mPermissionDataProvider = permissionDataProvider;
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
@@ -1239,7 +1247,7 @@ public final class Settings {
void writeAllRuntimePermissionsLPr() {
for (int userId : UserManagerService.getInstance().getUserIds()) {
- mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
}
}
@@ -2102,7 +2110,7 @@ public final class Settings {
}
void readInstallPermissionsLPr(XmlPullParser parser,
- PermissionsState permissionsState) throws IOException, XmlPullParserException {
+ AppIdPermissionState permissionsState) throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -2131,25 +2139,7 @@ public final class Settings {
final int flags = (flagsStr != null)
? Integer.parseInt(flagsStr, 16) : 0;
- if (granted) {
- if (permissionsState.grantInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
- XmlUtils.skipCurrentTag(parser);
- } else {
- permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- }
- } else {
- if (permissionsState.revokeInstallPermission(bp) ==
- PermissionsState.PERMISSION_OPERATION_FAILURE) {
- Slog.w(PackageManagerService.TAG, "Permission already added: " + name);
- XmlUtils.skipCurrentTag(parser);
- } else {
- permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- }
- }
+ permissionsState.putInstallPermissionState(new PermissionState(bp, granted, flags));
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <permissions>: "
+ parser.getName());
@@ -2158,7 +2148,7 @@ public final class Settings {
}
}
- void writePermissionsLPr(XmlSerializer serializer, List<PermissionState> permissionStates)
+ void writePermissionsLPr(XmlSerializer serializer, Collection<PermissionState> permissionStates)
throws IOException {
if (permissionStates.isEmpty()) {
return;
@@ -2641,7 +2631,11 @@ public final class Settings {
}
final boolean isDebug = pkg.pkg.isDebuggable();
- final int[] gids = pkg.getPermissionsState().computeGids(userIds);
+ final IntArray gids = new IntArray();
+ for (final int userId : userIds) {
+ gids.addAll(mPermissionDataProvider.getGidsForUid(UserHandle.getUid(userId,
+ pkg.appId)));
+ }
// Avoid any application that has a space in its path.
if (dataPath.indexOf(' ') >= 0)
@@ -2673,11 +2667,12 @@ public final class Settings {
sb.append(" ");
sb.append(AndroidPackageUtils.getSeInfo(pkg.pkg, pkg));
sb.append(" ");
- if (gids != null && gids.length > 0) {
- sb.append(gids[0]);
- for (int i = 1; i < gids.length; i++) {
+ final int gidsSize = gids.size();
+ if (gids != null && gids.size() > 0) {
+ sb.append(gids.get(0));
+ for (int i = 1; i < gidsSize; i++) {
sb.append(",");
- sb.append(gids[i]);
+ sb.append(gids.get(i));
}
} else {
sb.append("none");
@@ -4482,8 +4477,9 @@ public final class Settings {
}
void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag,
- ArraySet<String> permissionNames, PackageSetting ps, SimpleDateFormat sdf,
- Date date, List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
+ ArraySet<String> permissionNames, PackageSetting ps,
+ AppIdPermissionState permissionsState, SimpleDateFormat sdf, Date date,
+ List<UserInfo> users, boolean dumpAll, boolean dumpAllComponents) {
AndroidPackage pkg = ps.pkg;
if (checkinTag != null) {
pw.print(checkinTag);
@@ -4810,7 +4806,6 @@ public final class Settings {
}
if (ps.sharedUser == null || permissionNames != null || dumpAll) {
- PermissionsState permissionsState = ps.getPermissionsState();
dumpInstallPermissionsLPr(pw, prefix + " ", permissionNames, permissionsState);
}
@@ -4889,8 +4884,8 @@ public final class Settings {
}
if (ps.sharedUser == null) {
- PermissionsState permissionsState = ps.getPermissionsState();
- dumpGidsLPr(pw, prefix + " ", permissionsState.computeGids(user.id));
+ dumpGidsLPr(pw, prefix + " ", mPermissionDataProvider.getGidsForUid(
+ UserHandle.getUid(user.id, ps.appId)));
dumpRuntimePermissionsLPr(pw, prefix + " ", permissionNames, permissionsState
.getRuntimePermissionStates(user.id), dumpAll);
}
@@ -4933,8 +4928,10 @@ public final class Settings {
&& !packageName.equals(ps.name)) {
continue;
}
+ final AppIdPermissionState permissionsState =
+ mPermissionDataProvider.getAppIdPermissionState(ps.appId);
if (permissionNames != null
- && !ps.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ && !permissionsState.hasPermissionState(permissionNames)) {
continue;
}
@@ -4948,8 +4945,8 @@ public final class Settings {
pw.println("Packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, sdf, date, users,
- packageName != null, dumpAllComponents);
+ dumpPackageLPr(pw, " ", checkin ? "pkg" : null, permissionNames, ps, permissionsState,
+ sdf, date, users, packageName != null, dumpAllComponents);
}
printedSomething = false;
@@ -4989,8 +4986,10 @@ public final class Settings {
pw.println("Hidden system packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps, sdf, date,
- users, packageName != null, dumpAllComponents);
+ final AppIdPermissionState permissionsState =
+ mPermissionDataProvider.getAppIdPermissionState(ps.appId);
+ dumpPackageLPr(pw, " ", checkin ? "dis" : null, permissionNames, ps,
+ permissionsState, sdf, date, users, packageName != null, dumpAllComponents);
}
}
}
@@ -5018,8 +5017,10 @@ public final class Settings {
if (packageName != null && su != dumpState.getSharedUser()) {
continue;
}
+ final AppIdPermissionState permissionsState =
+ mPermissionDataProvider.getAppIdPermissionState(su.userId);
if (permissionNames != null
- && !su.getPermissionsState().hasRequestedPermission(permissionNames)) {
+ && !permissionsState.hasPermissionState(permissionNames)) {
continue;
}
if (!checkin) {
@@ -5054,12 +5055,12 @@ public final class Settings {
continue;
}
- final PermissionsState permissionsState = su.getPermissionsState();
dumpInstallPermissionsLPr(pw, prefix, permissionNames, permissionsState);
for (int userId : UserManagerService.getInstance().getUserIds()) {
- final int[] gids = permissionsState.computeGids(userId);
- final List<PermissionState> permissions =
+ final int[] gids = mPermissionDataProvider.getGidsForUid(UserHandle.getUid(
+ userId, su.userId));
+ final Collection<PermissionState> permissions =
permissionsState.getRuntimePermissionStates(userId);
if (!ArrayUtils.isEmpty(gids) || !permissions.isEmpty()) {
pw.print(prefix); pw.print("User "); pw.print(userId); pw.println(": ");
@@ -5120,7 +5121,7 @@ public final class Settings {
}
void dumpRuntimePermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
- List<PermissionState> permissionStates, boolean dumpAll) {
+ Collection<PermissionState> permissionStates, boolean dumpAll) {
if (!permissionStates.isEmpty() || dumpAll) {
pw.print(prefix); pw.println("runtime permissions:");
for (PermissionState permissionState : permissionStates) {
@@ -5161,8 +5162,9 @@ public final class Settings {
}
void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
- PermissionsState permissionsState) {
- List<PermissionState> permissionStates = permissionsState.getInstallPermissionStates();
+ AppIdPermissionState permissionsState) {
+ Collection<PermissionState> permissionStates =
+ permissionsState.getInstallPermissionStates();
if (!permissionStates.isEmpty()) {
pw.print(prefix); pw.println("install permissions:");
for (PermissionState permissionState : permissionStates) {
@@ -5202,9 +5204,9 @@ public final class Settings {
public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) {
if (sync) {
- mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserSyncLPr(userId);
} else {
- mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId);
+ mRuntimePermissionsPersistence.writeStateForUserAsyncLPr(userId);
}
}
@@ -5292,8 +5294,6 @@ public final class Settings {
private final Handler mHandler = new MyHandler();
- private final Object mPersistenceLock;
-
@GuardedBy("mLock")
private final SparseBooleanArray mWriteScheduled = new SparseBooleanArray();
@@ -5313,10 +5313,8 @@ public final class Settings {
// The mapping keys are user ids.
private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
- public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
- Object persistenceLock) {
+ public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence) {
mPersistence = persistence;
- mPersistenceLock = persistenceLock;
}
@GuardedBy("Settings.this.mLock")
@@ -5327,7 +5325,7 @@ public final class Settings {
@GuardedBy("Settings.this.mLock")
void setVersionLPr(int version, int userId) {
mVersions.put(userId, version);
- writePermissionsForUserAsyncLPr(userId);
+ writeStateForUserAsyncLPr(userId);
}
@GuardedBy("Settings.this.mLock")
@@ -5342,7 +5340,7 @@ public final class Settings {
+ "set before trying to update the fingerprint.");
}
mFingerprints.put(userId, mExtendedFingerprint);
- writePermissionsForUserAsyncLPr(userId);
+ writeStateForUserAsyncLPr(userId);
}
public void setPermissionControllerVersion(long version) {
@@ -5361,13 +5359,7 @@ public final class Settings {
return Build.FINGERPRINT + "?pc_version=" + version;
}
- public void writePermissionsForUserSyncLPr(int userId) {
- mHandler.removeMessages(userId);
- writePermissionsSync(userId);
- }
-
- @GuardedBy("Settings.this.mLock")
- public void writePermissionsForUserAsyncLPr(int userId) {
+ public void writeStateForUserAsyncLPr(int userId) {
final long currentTimeMillis = SystemClock.uptimeMillis();
if (mWriteScheduled.get(userId)) {
@@ -5399,59 +5391,53 @@ public final class Settings {
}
}
- private void writePermissionsSync(int userId) {
- RuntimePermissionsState runtimePermissions;
- synchronized (mPersistenceLock) {
- mWriteScheduled.delete(userId);
-
- int version = mVersions.get(userId, INITIAL_VERSION);
+ public void writeStateForUserSyncLPr(int userId) {
+ mHandler.removeMessages(userId);
+ mWriteScheduled.delete(userId);
- String fingerprint = mFingerprints.get(userId);
+ int version = mVersions.get(userId, INITIAL_VERSION);
- Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
- new ArrayMap<>();
- int packagesSize = mPackages.size();
- for (int i = 0; i < packagesSize; i++) {
- String packageName = mPackages.keyAt(i);
- PackageSetting packageSetting = mPackages.valueAt(i);
- if (packageSetting.sharedUser == null) {
- List<RuntimePermissionsState.PermissionState> permissions =
- getPermissionsFromPermissionsState(
- packageSetting.getPermissionsState(), userId);
- packagePermissions.put(packageName, permissions);
- }
- }
+ String fingerprint = mFingerprints.get(userId);
- Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
- new ArrayMap<>();
- final int sharedUsersSize = mSharedUsers.size();
- for (int i = 0; i < sharedUsersSize; i++) {
- String sharedUserName = mSharedUsers.keyAt(i);
- SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+ Map<String, List<RuntimePermissionsState.PermissionState>> packagePermissions =
+ new ArrayMap<>();
+ int packagesSize = mPackages.size();
+ for (int i = 0; i < packagesSize; i++) {
+ String packageName = mPackages.keyAt(i);
+ PackageSetting packageSetting = mPackages.valueAt(i);
+ if (packageSetting.sharedUser == null) {
List<RuntimePermissionsState.PermissionState> permissions =
getPermissionsFromPermissionsState(
- sharedUserSetting.getPermissionsState(), userId);
- sharedUserPermissions.put(sharedUserName, permissions);
+ packageSetting.getPermissionsState(), userId);
+ packagePermissions.put(packageName, permissions);
}
+ }
- runtimePermissions = new RuntimePermissionsState(version, fingerprint,
- packagePermissions, sharedUserPermissions);
+ Map<String, List<RuntimePermissionsState.PermissionState>> sharedUserPermissions =
+ new ArrayMap<>();
+ final int sharedUsersSize = mSharedUsers.size();
+ for (int i = 0; i < sharedUsersSize; i++) {
+ String sharedUserName = mSharedUsers.keyAt(i);
+ SharedUserSetting sharedUserSetting = mSharedUsers.valueAt(i);
+ List<RuntimePermissionsState.PermissionState> permissions =
+ getPermissionsFromPermissionsState(
+ sharedUserSetting.getPermissionsState(), userId);
+ sharedUserPermissions.put(sharedUserName, permissions);
}
+ RuntimePermissionsState runtimePermissions = new RuntimePermissionsState(version,
+ fingerprint, packagePermissions, sharedUserPermissions);
+
mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
private List<RuntimePermissionsState.PermissionState> getPermissionsFromPermissionsState(
- @NonNull PermissionsState permissionsState, @UserIdInt int userId) {
- List<PermissionState> permissionStates = permissionsState.getRuntimePermissionStates(
- userId);
- List<RuntimePermissionsState.PermissionState> permissions =
- new ArrayList<>();
- int permissionStatesSize = permissionStates.size();
- for (int i = 0; i < permissionStatesSize; i++) {
- PermissionState permissionState = permissionStates.get(i);
-
+ @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) {
+ Collection<PermissionState> permissionStates =
+ permissionsState.getRuntimePermissionStates(userId);
+ List<RuntimePermissionsState.PermissionState> permissions = new ArrayList<>();
+ for (PermissionState permissionState : permissionStates) {
RuntimePermissionsState.PermissionState permission =
new RuntimePermissionsState.PermissionState(permissionState.getName(),
permissionState.isGranted(), permissionState.getFlags());
@@ -5480,7 +5466,7 @@ public final class Settings {
userId));
if (runtimePermissions == null) {
readLegacyStateForUserSyncLPr(userId);
- writePermissionsForUserAsyncLPr(userId);
+ writeStateForUserAsyncLPr(userId);
return;
}
@@ -5536,7 +5522,7 @@ public final class Settings {
private void readPermissionsStateLpr(
@NonNull List<RuntimePermissionsState.PermissionState> permissions,
- @NonNull PermissionsState permissionsState, @UserIdInt int userId) {
+ @NonNull AppIdPermissionState permissionsState, @UserIdInt int userId) {
int permissionsSize = permissions.size();
for (int i = 0; i < permissionsSize; i++) {
RuntimePermissionsState.PermissionState permission = permissions.get(i);
@@ -5550,14 +5536,8 @@ public final class Settings {
boolean granted = permission.isGranted();
int flags = permission.getFlags();
- if (granted) {
- permissionsState.grantRuntimePermission(basePermission, userId);
- permissionsState.updatePermissionFlags(basePermission, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- } else {
- permissionsState.updatePermissionFlags(basePermission, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- }
+ permissionsState.putRuntimePermissionState(new PermissionState(basePermission,
+ granted, flags), userId);
}
}
@@ -5638,8 +5618,9 @@ public final class Settings {
}
}
- private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState,
- int userId) throws IOException, XmlPullParserException {
+ private void parsePermissionsLPr(XmlPullParser parser,
+ AppIdPermissionState permissionsState, int userId)
+ throws IOException, XmlPullParserException {
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -5666,15 +5647,8 @@ public final class Settings {
final int flags = (flagsStr != null)
? Integer.parseInt(flagsStr, 16) : 0;
- if (granted) {
- permissionsState.grantRuntimePermission(bp, userId);
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- } else {
- permissionsState.updatePermissionFlags(bp, userId,
- PackageManager.MASK_PERMISSION_FLAGS_ALL, flags);
- }
-
+ permissionsState.putRuntimePermissionState(new PermissionState(bp, granted,
+ flags), userId);
}
break;
}
@@ -5690,7 +5664,9 @@ public final class Settings {
public void handleMessage(Message message) {
final int userId = message.what;
Runnable callback = (Runnable) message.obj;
- writePermissionsSync(userId);
+ synchronized (mLock) {
+ writeStateForUserSyncLPr(userId);
+ }
if (callback != null) {
callback.run();
}
diff --git a/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java
new file mode 100644
index 000000000000..aabdafdd453a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/AppIdPermissionState.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+/**
+ * Legacy permission state that was associated with packages or shared users.
+ */
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public final class AppIdPermissionState {
+ // Maps from user IDs to user states.
+ @NonNull
+ private final SparseArray<UserState> mUserStates = new SparseArray<>();
+
+ // Keyed by user IDs.
+ @NonNull
+ private final SparseBooleanArray mMissing = new SparseBooleanArray();
+
+ /**
+ * Copy from another permission state.
+ *
+ * @param other the other permission state.
+ *
+ * @hide
+ */
+ public void copyFrom(@NonNull AppIdPermissionState other) {
+ if (other == this) {
+ return;
+ }
+
+ mUserStates.clear();
+ final int userStatesSize = other.mUserStates.size();
+ for (int i = 0; i < userStatesSize; i++) {
+ mUserStates.put(other.mUserStates.keyAt(i),
+ new UserState(other.mUserStates.valueAt(i)));
+ }
+
+ mMissing.clear();
+ final int missingSize = other.mMissing.size();
+ for (int i = 0; i < missingSize; i++) {
+ mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i));
+ }
+ }
+
+ /**
+ * Reset this permission state.
+ *
+ * @hide
+ */
+ public void reset() {
+ mUserStates.clear();
+ mMissing.clear();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null) {
+ return false;
+ }
+ if (getClass() != object.getClass()) {
+ return false;
+ }
+ final AppIdPermissionState other = (AppIdPermissionState) object;
+ return Objects.equals(mUserStates, other.mUserStates)
+ && Objects.equals(mMissing, other.mMissing);
+ }
+
+ /**
+ * Put a install permission state.
+ *
+ * @param permissionState the permission state
+ */
+ public void putInstallPermissionState(@NonNull PermissionState permissionState) {
+ putPermissionState(permissionState, UserHandle.USER_ALL);
+ }
+
+ /**
+ * Put a runtime permission state for a user.
+ *
+ * @param permissionState the permission state
+ * @param userId the user ID
+ */
+ public void putRuntimePermissionState(@NonNull PermissionState permissionState,
+ @UserIdInt int userId) {
+ checkUserId(userId);
+ putPermissionState(permissionState, userId);
+ }
+
+ private void putPermissionState(@NonNull PermissionState permissionState,
+ @UserIdInt int userId) {
+ UserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ userState = new UserState();
+ mUserStates.put(userId, userState);
+ }
+ userState.putPermissionState(permissionState);
+ }
+
+ /**
+ * Check whether there are any permission states for the given permissions.
+ *
+ * @param permissionNames the permission names
+ * @return whether there are any permission states
+ *
+ * @hide
+ */
+ public boolean hasPermissionState(@NonNull Collection<String> permissionNames) {
+ final int userStatesSize = mUserStates.size();
+ for (int i = 0; i < userStatesSize; i++) {
+ final UserState userState = mUserStates.valueAt(i);
+ for (final String permissionName : permissionNames) {
+ if (userState.getPermissionState(permissionName) != null) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get all the install permission states.
+ *
+ * @return the install permission states
+ */
+ @NonNull
+ public Collection<PermissionState> getInstallPermissionStates() {
+ return getPermissionStates(UserHandle.USER_ALL);
+ }
+
+ /**
+ * Get all the runtime permission states for a user.
+ *
+ * @param userId the user ID
+ * @return the runtime permission states
+ */
+ @NonNull
+ public Collection<PermissionState> getRuntimePermissionStates(@UserIdInt int userId) {
+ checkUserId(userId);
+ return getPermissionStates(userId);
+ }
+
+ @NonNull
+ private Collection<PermissionState> getPermissionStates(@UserIdInt int userId) {
+ final UserState userState = mUserStates.get(userId);
+ if (userState == null) {
+ return Collections.emptyList();
+ }
+ return userState.getPermissionStates();
+ }
+
+ /**
+ * Check whether the permission state is missing for a user.
+ * <p>
+ * This can happen if permission state is rolled back and we'll need to generate a reasonable
+ * default state to keep the app usable.
+ *
+ * @param userId the user ID
+ * @return whether the permission state is missing
+ */
+ public boolean isMissing(@UserIdInt int userId) {
+ checkUserId(userId);
+ return mMissing.get(userId);
+ }
+
+ /**
+ * Set whether the permission state is missing for a user.
+ * <p>
+ * This can happen if permission state is rolled back and we'll need to generate a reasonable
+ * default state to keep the app usable.
+ *
+ * @param missing whether the permission state is missing
+ * @param userId the user ID
+ */
+ public void setMissing(boolean missing, @UserIdInt int userId) {
+ checkUserId(userId);
+ if (missing) {
+ mMissing.put(userId, true);
+ } else {
+ mMissing.delete(userId);
+ }
+ }
+
+ private static void checkUserId(@UserIdInt int userId) {
+ if (userId < 0) {
+ throw new IllegalArgumentException("Invalid user ID " + userId);
+ }
+ }
+
+ /**
+ * Legacy state for permissions for a user.
+ */
+ private static final class UserState {
+ // Maps from permission names to permission states.
+ @NonNull
+ private final ArrayMap<String, PermissionState> mPermissionStates = new ArrayMap<>();
+
+ public UserState() {}
+
+ public UserState(@NonNull UserState other) {
+ final int permissionStatesSize = other.mPermissionStates.size();
+ for (int i = 0; i < permissionStatesSize; i++) {
+ mPermissionStates.put(other.mPermissionStates.keyAt(i),
+ new PermissionState(other.mPermissionStates.valueAt(i)));
+ }
+ }
+
+ @Nullable
+ public PermissionState getPermissionState(@NonNull String permissionName) {
+ return mPermissionStates.get(permissionName);
+ }
+
+ public void putPermissionState(@NonNull PermissionState permissionState) {
+ mPermissionStates.put(permissionState.getName(), permissionState);
+ }
+
+ @NonNull
+ public Collection<PermissionState> getPermissionStates() {
+ return Collections.unmodifiableCollection(mPermissionStates.values());
+ }
+ }
+
+ /**
+ * Legacy state for a single permission.
+ */
+ public static final class PermissionState {
+ @NonNull
+ private final BasePermission mPermission;
+
+ private final boolean mGranted;
+
+ private final int mFlags;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param permission the {@link BasePermission} for the permission
+ * @param granted whether the permission is granted
+ * @param flags the permission flags
+ */
+ public PermissionState(@NonNull BasePermission permission, boolean granted, int flags) {
+ mPermission = permission;
+ mGranted = granted;
+ mFlags = flags;
+ }
+
+ private PermissionState(@NonNull PermissionState other) {
+ mPermission = other.mPermission;
+ mGranted = other.mGranted;
+ mFlags = other.mFlags;
+ }
+
+ /**
+ * Get the {@link BasePermission} for the permission.
+ *
+ * @return the {@link BasePermission}
+ */
+ @NonNull
+ public BasePermission getPermission() {
+ return mPermission;
+ }
+
+ /**
+ * Get the permission name.
+ *
+ * @return the permission name
+ */
+ @NonNull
+ public String getName() {
+ return mPermission.getName();
+ }
+
+ /**
+ * Get whether the permission is granted.
+ *
+ * @return whether the permission is granted
+ */
+ @NonNull
+ public boolean isGranted() {
+ return mGranted;
+ }
+
+ /**
+ * Get the permission flags.
+ *
+ * @return the permission flags
+ */
+ @NonNull
+ public int getFlags() {
+ return mFlags;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
new file mode 100644
index 000000000000..7452b522b20a
--- /dev/null
+++ b/services/core/java/com/android/server/pm/permission/LegacyPermissionDataProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.permission;
+
+import android.annotation.AppIdInt;
+import android.annotation.NonNull;
+
+/**
+ * An interface for legacy code to read permission data in order to maintain compatibility.
+ */
+//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public interface LegacyPermissionDataProvider {
+ /**
+ * Get the legacy permission state of an app ID, either a package or a shared user.
+ *
+ * @param appId the app ID
+ * @return the legacy permission state
+ */
+ @NonNull
+ public abstract AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId);
+
+ /**
+ * Get the GIDs computed from the permission state of a UID, either a package or a shared user.
+ *
+ * @param uid the UID
+ * @return the GIDs for the UID
+ */
+ @NonNull
+ public abstract int[] getGidsForUid(int uid);
+}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index aa327ba02356..544f1225916e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -58,6 +58,7 @@ import static com.android.server.pm.permission.UidPermissionState.PERMISSION_OPE
import static java.util.concurrent.TimeUnit.SECONDS;
import android.Manifest;
+import android.annotation.AppIdInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -137,7 +138,6 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
-import com.android.server.am.ActivityManagerService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
@@ -902,16 +902,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private int checkPermissionImpl(String permName, String pkgName, int userId) {
- try {
- enforceCrossUserOrProfilePermission(Binder.getCallingUid(), userId,
- false, false, "checkPermissionImpl");
- } catch (Exception e) {
- Slog.e(TAG, "Invalid cross user access", e);
- EventLog.writeEvent(0x534e4554, "153996875", "checkPermissionImpl", pkgName);
-
- throw e;
- }
-
final AndroidPackage pkg = mPackageManagerInt.getPackage(pkgName);
if (pkg == null) {
return PackageManager.PERMISSION_DENIED;
@@ -989,16 +979,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
private int checkUidPermissionImpl(String permName, int uid) {
- try {
- enforceCrossUserOrProfilePermission(Binder.getCallingUid(), UserHandle.getUserId(uid),
- false, false, "checkUidPermissionImpl");
- } catch (Exception e) {
- Slog.e(TAG, "Invalid cross user access", e);
- EventLog.writeEvent(0x534e4554, "153996875", "checkUidPermissionImpl", uid);
-
- throw e;
- }
-
final AndroidPackage pkg = mPackageManagerInt.getPackage(uid);
return checkUidPermissionInternal(pkg, uid, permName);
}
@@ -2535,20 +2515,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return permission.computeGids(userId);
}
- @Nullable
- private int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
- final PackageSetting ps = mPackageManagerInt.getPackageSetting(packageName);
- if (ps == null) {
- return null;
- }
- final UidPermissionState uidState = getUidState(ps, userId);
- if (uidState == null) {
- Slog.e(TAG, "Missing permissions state for " + packageName + " and user " + userId);
- return null;
- }
- return uidState.computeGids(userId);
- }
-
/**
* Restore the permission state for a package.
*
@@ -4529,7 +4495,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(
- Binder.getCallingPid(), callingUid, callingUserId, userId, requireFullPermission,
+ callingUid, callingUserId, userId, requireFullPermission,
requirePermissionWhenSameUser)) {
return;
}
@@ -4556,79 +4522,53 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void enforceCrossUserOrProfilePermission(int callingUid, @UserIdInt int userId,
boolean requireFullPermission, boolean checkShell,
String message) {
- int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getUserId(callingUid);
-
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
-
- if (callingUserId == userId) {
+ if (checkShell) {
+ PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+ }
+ final int callingUserId = UserHandle.getUserId(callingUid);
+ if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
+ /*requirePermissionWhenSameUser= */ false)) {
return;
}
-
- // Prevent endless loop between when checking permission while checking a permission
- if (callingPid == ActivityManagerService.MY_PID) {
+ final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+ if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+ mContext,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ PermissionChecker.PID_UNKNOWN,
+ callingUid,
+ mPackageManagerInt.getPackage(callingUid).getPackageName())
+ == PermissionChecker.PERMISSION_GRANTED) {
return;
}
-
- long token = Binder.clearCallingIdentity();
- try {
- if (checkShell) {
- PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
- UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- if (hasCrossUserPermission(callingPid, callingUid, callingUserId, userId,
- requireFullPermission, /*requirePermissionWhenSameUser= */ false)) {
- return;
- }
- final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
-
- if (isSameProfileGroup) {
- AndroidPackage callingPkg = mPackageManagerInt.getPackage(callingUid);
- String callingPkgName = null;
- if (callingPkg != null) {
- callingPkgName = callingPkg.getPackageName();
- }
-
- if (PermissionChecker.checkPermissionForPreflight(
- mContext,
- android.Manifest.permission.INTERACT_ACROSS_PROFILES,
- PermissionChecker.PID_UNKNOWN,
- callingUid,
- callingPkgName)
- == PermissionChecker.PERMISSION_GRANTED) {
- return;
- }
- }
-
String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
callingUid, userId, message, requireFullPermission, isSameProfileGroup);
Slog.w(TAG, errorMessage);
throw new SecurityException(errorMessage);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
}
- private boolean hasCrossUserPermission(int callingPid, int callingUid, int callingUserId,
- int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) {
+ private boolean hasCrossUserPermission(
+ int callingUid, int callingUserId, int userId, boolean requireFullPermission,
+ boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
return true;
}
if (callingUid == Process.SYSTEM_UID || callingUid == Process.ROOT_UID) {
return true;
}
-
- if (!requireFullPermission) {
- if (mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
+ if (requireFullPermission) {
+ return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
+ return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
+ }
- return mContext.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
+ private boolean hasPermission(String permission) {
+ return mContext.checkCallingOrSelfPermission(permission)
+ == PackageManager.PERMISSION_GRANTED;
}
private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
@@ -4813,7 +4753,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private void removeAppState(int appId) {
+ private void removeAppIdState(@AppIdInt int appId) {
synchronized (mLock) {
final int[] userIds = mState.getUserIds();
for (final int userId : userIds) {
@@ -4827,7 +4767,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int[] userIds = getAllUserIds();
mPackageManagerInt.forEachPackageSetting(ps -> {
final int appId = ps.getAppId();
- final PermissionsState permissionsState = ps.getPermissionsState();
+ final AppIdPermissionState appIdState = ps.getPermissionsState();
synchronized (mLock) {
for (final int userId : userIds) {
@@ -4836,25 +4776,22 @@ public class PermissionManagerService extends IPermissionManager.Stub {
userState.setInstallPermissionsFixed(ps.name, ps.areInstallPermissionsFixed());
final UidPermissionState uidState = userState.getOrCreateUidState(appId);
uidState.reset();
- uidState.setGlobalGids(permissionsState.getGlobalGids());
- uidState.setMissing(permissionsState.isMissing(userId));
+ uidState.setMissing(appIdState.isMissing(userId));
readStateFromPermissionStates(uidState,
- permissionsState.getInstallPermissionStates(), false);
+ appIdState.getInstallPermissionStates(), false);
readStateFromPermissionStates(uidState,
- permissionsState.getRuntimePermissionStates(userId), true);
+ appIdState.getRuntimePermissionStates(userId), true);
}
}
});
}
private void readStateFromPermissionStates(@NonNull UidPermissionState uidState,
- @NonNull List<PermissionsState.PermissionState> permissionStates, boolean isRuntime) {
- final int permissionStatesSize = permissionStates.size();
- for (int i = 0; i < permissionStatesSize; i++) {
- final PermissionsState.PermissionState permissionState = permissionStates.get(i);
- final BasePermission permission = permissionState.getPermission();
- uidState.putPermissionState(permission, isRuntime, permissionState.isGranted(),
- permissionState.getFlags());
+ @NonNull Collection<AppIdPermissionState.PermissionState> permissionStates,
+ boolean isRuntime) {
+ for (final AppIdPermissionState.PermissionState permissionState : permissionStates) {
+ uidState.putPermissionState(permissionState.getPermission(), isRuntime,
+ permissionState.isGranted(), permissionState.getFlags());
}
}
@@ -4862,8 +4799,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int[] userIds = mState.getUserIds();
mPackageManagerInt.forEachPackageSetting(ps -> {
ps.setInstallPermissionsFixed(false);
- final PermissionsState permissionsState = ps.getPermissionsState();
- permissionsState.reset();
+ final AppIdPermissionState appIdState = ps.getPermissionsState();
+ appIdState.reset();
final int appId = ps.getAppId();
synchronized (mLock) {
@@ -4885,27 +4822,21 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- permissionsState.setGlobalGids(uidState.getGlobalGids());
- permissionsState.setMissing(uidState.isMissing(), userId);
+ appIdState.setMissing(uidState.isMissing(), userId);
final List<PermissionState> permissionStates = uidState.getPermissionStates();
final int permissionStatesSize = permissionStates.size();
for (int i = 0; i < permissionStatesSize; i++) {
final PermissionState permissionState = permissionStates.get(i);
- final BasePermission permission = permissionState.getPermission();
- if (permissionState.isGranted()) {
- if (permissionState.isRuntime()) {
- permissionsState.grantRuntimePermission(permission, userId);
- } else {
- permissionsState.grantInstallPermission(permission);
- }
- }
- final int flags = permissionState.getFlags();
- if (flags != 0) {
- final int flagsUserId = permissionState.isRuntime() ? userId
- : UserHandle.USER_ALL;
- permissionsState.updatePermissionFlags(permission, flagsUserId, flags,
- flags);
+ final AppIdPermissionState.PermissionState legacyPermissionState =
+ new AppIdPermissionState.PermissionState(
+ permissionState.getPermission(),
+ permissionState.isGranted(), permissionState.getFlags());
+ if (permissionState.isRuntime()) {
+ appIdState.putRuntimePermissionState(legacyPermissionState,
+ userId);
+ } else {
+ appIdState.putInstallPermissionState(legacyPermissionState);
}
}
}
@@ -4913,6 +4844,48 @@ public class PermissionManagerService extends IPermissionManager.Stub {
});
}
+ @NonNull
+ private AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) {
+ final AppIdPermissionState appIdState = new AppIdPermissionState();
+ final int[] userIds = mState.getUserIds();
+ for (final int userId : userIds) {
+ final UidPermissionState uidState = getUidState(appId, userId);
+ if (uidState == null) {
+ Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID "
+ + userId);
+ continue;
+ }
+
+ final List<PermissionState> permissionStates = uidState.getPermissionStates();
+ final int permissionStatesSize = permissionStates.size();
+ for (int i = 0; i < permissionStatesSize; i++) {
+ final PermissionState permissionState = permissionStates.get(i);
+
+ final AppIdPermissionState.PermissionState legacyPermissionState =
+ new AppIdPermissionState.PermissionState(permissionState.getPermission(),
+ permissionState.isGranted(), permissionState.getFlags());
+ if (permissionState.isRuntime()) {
+ appIdState.putRuntimePermissionState(legacyPermissionState, userId);
+ } else if (userId == UserHandle.USER_SYSTEM) {
+ appIdState.putInstallPermissionState(legacyPermissionState);
+ }
+ }
+ }
+ return appIdState;
+ }
+
+ @NonNull
+ private int[] getGidsForUid(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final int userId = UserHandle.getUserId(uid);
+ final UidPermissionState uidState = getUidState(appId, userId);
+ if (uidState == null) {
+ Slog.e(TAG, "Missing permissions state for app ID " + appId + " and user ID " + userId);
+ return EMPTY_INT_ARRAY;
+ }
+ return uidState.computeGids(userId);
+ }
+
private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal {
@Override
public void systemReady() {
@@ -4957,8 +4930,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
PermissionManagerService.this.onUserRemoved(userId);
}
@Override
- public void removePermissionsStateTEMP(int appId) {
- PermissionManagerService.this.removeAppState(appId);
+ public void removeAppIdStateTEMP(@AppIdInt int appId) {
+ PermissionManagerService.this.removeAppIdState(appId);
}
@Override
@UserIdInt
@@ -4978,11 +4951,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
public int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId) {
return PermissionManagerService.this.getPermissionGids(permissionName, userId);
}
- @Nullable
- @Override
- public int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId) {
- return PermissionManagerService.this.getPackageGids(packageName, userId);
- }
@Override
public void grantRequestedRuntimePermissions(AndroidPackage pkg, int[] userIds,
String[] grantedPermissions, int callingUid) {
@@ -5310,6 +5278,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
}
+
+ @NonNull
+ public AppIdPermissionState getAppIdPermissionState(@AppIdInt int appId) {
+ return PermissionManagerService.this.getAppIdPermissionState(appId);
+ }
+
+ @NonNull
+ public int[] getGidsForUid(int uid) {
+ return PermissionManagerService.this.getGidsForUid(uid);
+ }
}
private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 6d9bd2a1b30d..5ea3458fcbfa 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -37,8 +37,8 @@ import java.util.function.Consumer;
*
* TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
-public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
-
+public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal
+ implements LegacyPermissionDataProvider {
/**
* Provider for package names.
*/
@@ -288,13 +288,13 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void onUserRemoved(@UserIdInt int userId);
/**
- * Remove the {@code PermissionsState} associated with an app ID, called the same time as the
+ * Remove the permission state associated with an app ID, called the same time as the
* removal of a {@code PackageSetitng}.
*
* TODO(zhanghai): This is a temporary method before we figure out a way to get notified of app
* ID removal via API.
*/
- public abstract void removePermissionsStateTEMP(int appId);
+ public abstract void removeAppIdStateTEMP(@AppIdInt int appId);
/**
* Update the shared user setting when a package with a shared user id is removed. The gids
@@ -324,12 +324,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
@Nullable
public abstract int[] getPermissionGids(@NonNull String permissionName, @UserIdInt int userId);
- /**
- * Get the GIDs computed from the permission state of a package.
- */
- @Nullable
- public abstract int[] getPackageGids(@NonNull String packageName, @UserIdInt int userId);
-
/** Retrieve the packages that have requested the given app op permission */
public abstract @Nullable String[] getAppOpPermissionPackages(
@NonNull String permName, int callingUid);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionsState.java b/services/core/java/com/android/server/pm/permission/PermissionsState.java
deleted file mode 100644
index 4fb2d5fc200e..000000000000
--- a/services/core/java/com/android/server/pm/permission/PermissionsState.java
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.permission;
-
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * This class encapsulates the permissions for a package or a shared user.
- * <p>
- * There are two types of permissions: install (granted at installation)
- * and runtime (granted at runtime). Install permissions are granted to
- * all device users while runtime permissions are granted explicitly to
- * specific users.
- * </p>
- * <p>
- * The permissions are kept on a per device user basis. For example, an
- * application may have some runtime permissions granted under the device
- * owner but not granted under the secondary user.
- * <p>
- * This class is also responsible for keeping track of the Linux gids per
- * user for a package or a shared user. The gids are computed as a set of
- * the gids for all granted permissions' gids on a per user basis.
- * </p>
- */
-public final class PermissionsState {
-
- /** The permission operation failed. */
- public static final int PERMISSION_OPERATION_FAILURE = -1;
-
- /** The permission operation succeeded and no gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS = 0;
-
- /** The permission operation succeeded and gids changed. */
- public static final int PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED = 1;
-
- private static final int[] NO_GIDS = {};
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private ArrayMap<String, PermissionData> mPermissions;
-
- private int[] mGlobalGids = NO_GIDS;
-
- @Nullable
- private SparseBooleanArray mMissing;
-
- private SparseBooleanArray mPermissionReviewRequired;
-
- public PermissionsState() {
- /* do nothing */
- }
-
- public PermissionsState(PermissionsState prototype) {
- copyFrom(prototype);
- }
-
- public int[] getGlobalGids() {
- return mGlobalGids;
- }
-
- /**
- * Sets the global gids, applicable to all users.
- *
- * @param globalGids The global gids.
- */
- public void setGlobalGids(int[] globalGids) {
- if (!ArrayUtils.isEmpty(globalGids)) {
- mGlobalGids = Arrays.copyOf(globalGids, globalGids.length);
- }
- }
-
- private static void invalidateCache() {
- PackageManager.invalidatePackageInfoCache();
- }
-
- /**
- * Initialized this instance from another one.
- *
- * @param other The other instance.
- */
- public void copyFrom(PermissionsState other) {
- if (other == this) {
- return;
- }
-
- synchronized (mLock) {
- if (mPermissions != null) {
- if (other.mPermissions == null) {
- mPermissions = null;
- } else {
- mPermissions.clear();
- }
- }
- if (other.mPermissions != null) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- final int permissionCount = other.mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String name = other.mPermissions.keyAt(i);
- PermissionData permissionData = other.mPermissions.valueAt(i);
- mPermissions.put(name, new PermissionData(permissionData));
- }
- }
- }
-
- mGlobalGids = NO_GIDS;
- if (other.mGlobalGids != NO_GIDS) {
- mGlobalGids = Arrays.copyOf(other.mGlobalGids,
- other.mGlobalGids.length);
- }
-
- if (mMissing != null) {
- if (other.mMissing == null) {
- mMissing = null;
- } else {
- mMissing.clear();
- }
- }
- if (other.mMissing != null) {
- if (mMissing == null) {
- mMissing = new SparseBooleanArray();
- }
- final int missingSize = other.mMissing.size();
- for (int i = 0; i < missingSize; i++) {
- mMissing.put(other.mMissing.keyAt(i), other.mMissing.valueAt(i));
- }
- }
-
- if (mPermissionReviewRequired != null) {
- if (other.mPermissionReviewRequired == null) {
- mPermissionReviewRequired = null;
- } else {
- mPermissionReviewRequired.clear();
- }
- }
- if (other.mPermissionReviewRequired != null) {
- if (mPermissionReviewRequired == null) {
- mPermissionReviewRequired = new SparseBooleanArray();
- }
- final int userCount = other.mPermissionReviewRequired.size();
- for (int i = 0; i < userCount; i++) {
- final boolean reviewRequired = other.mPermissionReviewRequired.valueAt(i);
- mPermissionReviewRequired.put(other.mPermissionReviewRequired.keyAt(i),
- reviewRequired);
- }
- }
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- final PermissionsState other = (PermissionsState) obj;
-
- synchronized (mLock) {
- if (mPermissions == null) {
- if (other.mPermissions != null) {
- return false;
- }
- } else if (!mPermissions.equals(other.mPermissions)) {
- return false;
- }
- }
-
- if (!Objects.equals(mMissing, other.mMissing)) {
- return false;
- }
-
- if (mPermissionReviewRequired == null) {
- if (other.mPermissionReviewRequired != null) {
- return false;
- }
- } else if (!mPermissionReviewRequired.equals(other.mPermissionReviewRequired)) {
- return false;
- }
- return Arrays.equals(mGlobalGids, other.mGlobalGids);
- }
-
- /**
- * Check whether the permissions state is missing for a user. This can happen if permission
- * state is rolled back and we'll need to generate a reasonable default state to keep the app
- * usable.
- */
- public boolean isMissing(@UserIdInt int userId) {
- return mMissing != null && mMissing.get(userId);
- }
-
- /**
- * Set whether the permissions state is missing for a user. This can happen if permission state
- * is rolled back and we'll need to generate a reasonable default state to keep the app usable.
- */
- public void setMissing(boolean missing, @UserIdInt int userId) {
- if (missing) {
- if (mMissing == null) {
- mMissing = new SparseBooleanArray();
- }
- mMissing.put(userId, true);
- } else {
- if (mMissing != null) {
- mMissing.delete(userId);
- if (mMissing.size() == 0) {
- mMissing = null;
- }
- }
- }
- }
-
- public boolean isPermissionReviewRequired(int userId) {
- return mPermissionReviewRequired != null && mPermissionReviewRequired.get(userId);
- }
-
- /**
- * Grant an install permission.
- *
- * @param permission The permission to grant.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int grantInstallPermission(BasePermission permission) {
- return grantPermission(permission, UserHandle.USER_ALL);
- }
-
- /**
- * Revoke an install permission.
- *
- * @param permission The permission to revoke.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int revokeInstallPermission(BasePermission permission) {
- return revokePermission(permission, UserHandle.USER_ALL);
- }
-
- /**
- * Grant a runtime permission for a given device user.
- *
- * @param permission The permission to grant.
- * @param userId The device user id.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int grantRuntimePermission(BasePermission permission, int userId) {
- enforceValidUserId(userId);
- if (userId == UserHandle.USER_ALL) {
- return PERMISSION_OPERATION_FAILURE;
- }
- return grantPermission(permission, userId);
- }
-
- /**
- * Revoke a runtime permission for a given device user.
- *
- * @param permission The permission to revoke.
- * @param userId The device user id.
- * @return The operation result which is either {@link #PERMISSION_OPERATION_SUCCESS},
- * or {@link #PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED}, or {@link
- * #PERMISSION_OPERATION_FAILURE}.
- */
- public int revokeRuntimePermission(BasePermission permission, int userId) {
- enforceValidUserId(userId);
- if (userId == UserHandle.USER_ALL) {
- return PERMISSION_OPERATION_FAILURE;
- }
- return revokePermission(permission, userId);
- }
-
- /**
- * Gets whether this state has a given runtime permission for a
- * given device user id.
- *
- * @param name The permission name.
- * @param userId The device user id.
- * @return Whether this state has the permission.
- */
- public boolean hasRuntimePermission(String name, int userId) {
- enforceValidUserId(userId);
- return !hasInstallPermission(name) && hasPermission(name, userId);
- }
-
- /**
- * Gets whether this state has a given install permission.
- *
- * @param name The permission name.
- * @return Whether this state has the permission.
- */
- public boolean hasInstallPermission(String name) {
- return hasPermission(name, UserHandle.USER_ALL);
- }
-
- /**
- * Gets whether the state has a given permission for the specified
- * user, regardless if this is an install or a runtime permission.
- *
- * @param name The permission name.
- * @param userId The device user id.
- * @return Whether the user has the permission.
- */
- public boolean hasPermission(String name, int userId) {
- enforceValidUserId(userId);
-
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- PermissionData permissionData = mPermissions.get(name);
-
- return permissionData != null && permissionData.isGranted(userId);
- }
-
- }
-
- /**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
- */
- public boolean hasRequestedPermission(ArraySet<String> names) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- for (int i=names.size()-1; i>=0; i--) {
- if (mPermissions.get(names.valueAt(i)) != null) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the state has any known request for the given permission name,
- * whether or not it has been granted.
- */
- public boolean hasRequestedPermission(String name) {
- return mPermissions != null && (mPermissions.get(name) != null);
- }
- /**
- * Gets all permissions for a given device user id regardless if they
- * are install time or runtime permissions.
- *
- * @param userId The device user id.
- * @return The permissions or an empty set.
- */
- public Set<String> getPermissions(int userId) {
- enforceValidUserId(userId);
-
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptySet();
- }
-
- Set<String> permissions = new ArraySet<>(mPermissions.size());
-
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String permission = mPermissions.keyAt(i);
-
- if (hasInstallPermission(permission)) {
- permissions.add(permission);
- continue;
- }
-
- if (userId != UserHandle.USER_ALL) {
- if (hasRuntimePermission(permission, userId)) {
- permissions.add(permission);
- }
- }
- }
-
- return permissions;
- }
- }
-
- /**
- * Gets the state for an install permission or null if no such.
- *
- * @param name The permission name.
- * @return The permission state.
- */
- public PermissionState getInstallPermissionState(String name) {
- return getPermissionState(name, UserHandle.USER_ALL);
- }
-
- /**
- * Gets the state for a runtime permission or null if no such.
- *
- * @param name The permission name.
- * @param userId The device user id.
- * @return The permission state.
- */
- public PermissionState getRuntimePermissionState(String name, int userId) {
- enforceValidUserId(userId);
- return getPermissionState(name, userId);
- }
-
- /**
- * Gets all install permission states.
- *
- * @return The permission states or an empty set.
- */
- public List<PermissionState> getInstallPermissionStates() {
- return getPermissionStatesInternal(UserHandle.USER_ALL);
- }
-
- /**
- * Gets all runtime permission states.
- *
- * @return The permission states or an empty set.
- */
- public List<PermissionState> getRuntimePermissionStates(int userId) {
- enforceValidUserId(userId);
- return getPermissionStatesInternal(userId);
- }
-
- /**
- * Gets the flags for a permission regardless if it is install or
- * runtime permission.
- *
- * @param name The permission name.
- * @return The permission state or null if no such.
- */
- public int getPermissionFlags(String name, int userId) {
- PermissionState installPermState = getInstallPermissionState(name);
- if (installPermState != null) {
- return installPermState.getFlags();
- }
- PermissionState runtimePermState = getRuntimePermissionState(name, userId);
- if (runtimePermState != null) {
- return runtimePermState.getFlags();
- }
- return 0;
- }
-
- /**
- * Update the flags associated with a given permission.
- * @param permission The permission whose flags to update.
- * @param userId The user for which to update.
- * @param flagMask Mask for which flags to change.
- * @param flagValues New values for the mask flags.
- * @return Whether the permission flags changed.
- */
- public boolean updatePermissionFlags(BasePermission permission, int userId,
- int flagMask, int flagValues) {
- enforceValidUserId(userId);
-
- final boolean mayChangeFlags = flagValues != 0 || flagMask != 0;
-
- synchronized (mLock) {
- if (mPermissions == null) {
- if (!mayChangeFlags) {
- return false;
- }
- ensurePermissionData(permission);
- }
- }
-
- PermissionData permissionData = null;
- synchronized (mLock) {
- permissionData = mPermissions.get(permission.getName());
- }
-
- if (permissionData == null) {
- if (!mayChangeFlags) {
- return false;
- }
- permissionData = ensurePermissionData(permission);
- }
-
- final int oldFlags = permissionData.getFlags(userId);
-
- final boolean updated = permissionData.updateFlags(userId, flagMask, flagValues);
- if (updated) {
- final int newFlags = permissionData.getFlags(userId);
- if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- if (mPermissionReviewRequired == null) {
- mPermissionReviewRequired = new SparseBooleanArray();
- }
- mPermissionReviewRequired.put(userId, true);
- } else if ((oldFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0
- && (newFlags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- if (mPermissionReviewRequired != null && !hasPermissionRequiringReview(userId)) {
- mPermissionReviewRequired.delete(userId);
- if (mPermissionReviewRequired.size() <= 0) {
- mPermissionReviewRequired = null;
- }
- }
- }
- }
- return updated;
- }
-
- private boolean hasPermissionRequiringReview(int userId) {
- synchronized (mLock) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- final PermissionData permission = mPermissions.valueAt(i);
- if ((permission.getFlags(userId)
- & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public boolean updatePermissionFlagsForAllPermissions(
- int userId, int flagMask, int flagValues) {
- enforceValidUserId(userId);
-
- synchronized (mLock) {
- if (mPermissions == null) {
- return false;
- }
- boolean changed = false;
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionData permissionData = mPermissions.valueAt(i);
- changed |= permissionData.updateFlags(userId, flagMask, flagValues);
- }
-
- return changed;
- }
- }
-
- /**
- * Compute the Linux gids for a given device user from the permissions
- * granted to this user. Note that these are computed to avoid additional
- * state as they are rarely accessed.
- *
- * @param userId The device user id.
- * @return The gids for the device user.
- */
- public int[] computeGids(int userId) {
- enforceValidUserId(userId);
-
- int[] gids = mGlobalGids;
-
- synchronized (mLock) {
- if (mPermissions != null) {
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- String permission = mPermissions.keyAt(i);
- if (!hasPermission(permission, userId)) {
- continue;
- }
- PermissionData permissionData = mPermissions.valueAt(i);
- final int[] permGids = permissionData.computeGids(userId);
- if (permGids != NO_GIDS) {
- gids = appendInts(gids, permGids);
- }
- }
- }
- }
-
- return gids;
- }
-
- /**
- * Compute the Linux gids for all device users from the permissions
- * granted to these users.
- *
- * @return The gids for all device users.
- */
- public int[] computeGids(int[] userIds) {
- int[] gids = mGlobalGids;
-
- for (int userId : userIds) {
- final int[] userGids = computeGids(userId);
- gids = appendInts(gids, userGids);
- }
-
- return gids;
- }
-
- /**
- * Resets the internal state of this object.
- */
- public void reset() {
- mGlobalGids = NO_GIDS;
-
- synchronized (mLock) {
- mPermissions = null;
- invalidateCache();
- }
-
- mMissing = null;
- mPermissionReviewRequired = null;
- }
-
- private PermissionState getPermissionState(String name, int userId) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return null;
- }
- PermissionData permissionData = mPermissions.get(name);
- if (permissionData == null) {
- return null;
- }
-
- return permissionData.getPermissionState(userId);
- }
- }
-
- private List<PermissionState> getPermissionStatesInternal(int userId) {
- enforceValidUserId(userId);
-
- synchronized (mLock) {
- if (mPermissions == null) {
- return Collections.emptyList();
- }
-
- List<PermissionState> permissionStates = new ArrayList<>();
-
- final int permissionCount = mPermissions.size();
- for (int i = 0; i < permissionCount; i++) {
- PermissionData permissionData = mPermissions.valueAt(i);
-
- PermissionState permissionState = permissionData.getPermissionState(userId);
- if (permissionState != null) {
- permissionStates.add(permissionState);
- }
- }
-
- return permissionStates;
- }
- }
-
- private int grantPermission(BasePermission permission, int userId) {
- if (hasPermission(permission.getName(), userId)) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
- final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
-
- PermissionData permissionData = ensurePermissionData(permission);
-
- if (!permissionData.grant(userId)) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- if (hasGids) {
- final int[] newGids = computeGids(userId);
- if (oldGids.length != newGids.length) {
- return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
- }
- }
-
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- private int revokePermission(BasePermission permission, int userId) {
- final String permName = permission.getName();
- if (!hasPermission(permName, userId)) {
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
- final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
-
- PermissionData permissionData = null;
- synchronized (mLock) {
- permissionData = mPermissions.get(permName);
- }
-
- if (!permissionData.revoke(userId)) {
- return PERMISSION_OPERATION_FAILURE;
- }
-
- if (permissionData.isDefault()) {
- ensureNoPermissionData(permName);
- }
-
- if (hasGids) {
- final int[] newGids = computeGids(userId);
- if (oldGids.length != newGids.length) {
- return PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
- }
- }
-
- return PERMISSION_OPERATION_SUCCESS;
- }
-
- // TODO: fix this to use arraycopy and append all ints in one go
- private static int[] appendInts(int[] current, int[] added) {
- if (current != null && added != null) {
- for (int guid : added) {
- current = ArrayUtils.appendInt(current, guid);
- }
- }
- return current;
- }
-
- private static void enforceValidUserId(int userId) {
- if (userId != UserHandle.USER_ALL && userId < 0) {
- throw new IllegalArgumentException("Invalid userId:" + userId);
- }
- }
-
- private PermissionData ensurePermissionData(BasePermission permission) {
- final String permName = permission.getName();
-
- synchronized (mLock) {
- if (mPermissions == null) {
- mPermissions = new ArrayMap<>();
- }
- PermissionData permissionData = mPermissions.get(permName);
- if (permissionData == null) {
- permissionData = new PermissionData(permission);
- mPermissions.put(permName, permissionData);
- }
- return permissionData;
- }
-
- }
-
- private void ensureNoPermissionData(String name) {
- synchronized (mLock) {
- if (mPermissions == null) {
- return;
- }
- mPermissions.remove(name);
- if (mPermissions.isEmpty()) {
- mPermissions = null;
- }
- }
-
- }
-
- private static final class PermissionData {
-
- private final Object mLock = new Object();
-
- private final BasePermission mPerm;
- @GuardedBy("mLock")
- private SparseArray<PermissionState> mUserStates = new SparseArray<>();
-
- public PermissionData(BasePermission perm) {
- mPerm = perm;
- }
-
- public PermissionData(PermissionData other) {
- this(other.mPerm);
-
- synchronized (mLock) {
- final int otherStateCount = other.mUserStates.size();
- for (int i = 0; i < otherStateCount; i++) {
- final int otherUserId = other.mUserStates.keyAt(i);
- PermissionState otherState = other.mUserStates.valueAt(i);
- mUserStates.put(otherUserId, new PermissionState(otherState));
- }
- }
- }
-
- public int[] computeGids(int userId) {
- return mPerm.computeGids(userId);
- }
-
- public boolean isGranted(int userId) {
- synchronized (mLock) {
- if (isInstallPermission()) {
- userId = UserHandle.USER_ALL;
- }
-
- PermissionState userState = mUserStates.get(userId);
- if (userState == null) {
- return false;
- }
-
- return userState.mGranted;
- }
- }
-
- public boolean grant(int userId) {
- synchronized (mLock) {
- if (!isCompatibleUserId(userId)) {
- return false;
- }
-
- if (isGranted(userId)) {
- return false;
- }
-
- PermissionState userState = mUserStates.get(userId);
- if (userState == null) {
- userState = new PermissionState(mPerm);
- mUserStates.put(userId, userState);
- }
-
- userState.mGranted = true;
-
- invalidateCache();
- return true;
- }
- }
-
- public boolean revoke(int userId) {
- synchronized (mLock) {
- if (!isCompatibleUserId(userId)) {
- return false;
- }
-
- if (!isGranted(userId)) {
- return false;
- }
-
- PermissionState userState = mUserStates.get(userId);
- userState.mGranted = false;
-
- if (userState.isDefault()) {
- mUserStates.remove(userId);
- }
-
- invalidateCache();
- return true;
- }
- }
-
- public PermissionState getPermissionState(int userId) {
- synchronized (mLock) {
- return mUserStates.get(userId);
- }
- }
-
- public int getFlags(int userId) {
- synchronized (mLock) {
- PermissionState userState = mUserStates.get(userId);
- if (userState != null) {
- return userState.mFlags;
- }
- return 0;
- }
- }
-
- public boolean isDefault() {
- synchronized (mLock) {
- return mUserStates.size() <= 0;
- }
- }
-
- public static boolean isInstallPermissionKey(int userId) {
- return userId == UserHandle.USER_ALL;
- }
-
- public boolean updateFlags(int userId, int flagMask, int flagValues) {
- synchronized (mLock) {
- if (isInstallPermission()) {
- userId = UserHandle.USER_ALL;
- }
-
- if (!isCompatibleUserId(userId)) {
- return false;
- }
-
- final int newFlags = flagValues & flagMask;
-
- // Okay to do before the modification because we hold the lock.
- invalidateCache();
-
- PermissionState userState = mUserStates.get(userId);
- if (userState != null) {
- final int oldFlags = userState.mFlags;
- userState.mFlags = (userState.mFlags & ~flagMask) | newFlags;
- if (userState.isDefault()) {
- mUserStates.remove(userId);
- }
- return userState.mFlags != oldFlags;
- } else if (newFlags != 0) {
- userState = new PermissionState(mPerm);
- userState.mFlags = newFlags;
- mUserStates.put(userId, userState);
- return true;
- }
-
- return false;
- }
- }
-
- private boolean isCompatibleUserId(int userId) {
- return isDefault() || !(isInstallPermission() ^ isInstallPermissionKey(userId));
- }
-
- private boolean isInstallPermission() {
- return mUserStates.size() == 1
- && mUserStates.get(UserHandle.USER_ALL) != null;
- }
- }
-
- public static final class PermissionState {
- private final BasePermission mPermission;
- private boolean mGranted;
- private int mFlags;
-
- public PermissionState(BasePermission permission) {
- mPermission = permission;
- }
-
- public PermissionState(PermissionState other) {
- mPermission = other.mPermission;
- mGranted = other.mGranted;
- mFlags = other.mFlags;
- }
-
- public boolean isDefault() {
- return !mGranted && mFlags == 0;
- }
-
- public BasePermission getPermission() {
- return mPermission;
- }
-
- public String getName() {
- return mPermission.getName();
- }
-
- public boolean isGranted() {
- return mGranted;
- }
-
- public int getFlags() {
- return mFlags;
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 65dc320eadc2..c0d71ac26853 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,24 +18,21 @@
]
},
{
- "name": "CtsPermission2TestCases",
+ "name": "CtsAppSecurityHostTestCases",
"options": [
{
- "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
- },
- {
- "include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
+ "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
}
]
},
{
- "name": "CtsPermissionHostTestCases"
- },
- {
- "name": "CtsAppSecurityHostTestCases",
+ "name": "CtsPermission2TestCases",
"options": [
{
- "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
+ "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
}
]
},
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
index 1d31285ed9c7..de8823c4b7f3 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/ConversionUtil.java
@@ -40,7 +40,10 @@ import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundModelType;
import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
import android.os.HidlMemoryUtil;
+import android.os.ParcelFileDescriptor;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.util.regex.Matcher;
/**
@@ -196,8 +199,18 @@ class ConversionUtil {
hidlModel.header.type = aidl2hidlSoundModelType(aidlModel.type);
hidlModel.header.uuid = aidl2hidlUuid(aidlModel.uuid);
hidlModel.header.vendorUuid = aidl2hidlUuid(aidlModel.vendorUuid);
- hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(aidlModel.data,
- aidlModel.dataSize);
+
+ // Extract a dup of the underlying FileDescriptor out of aidlModel.data without changing
+ // the original.
+ FileDescriptor fd = new FileDescriptor();
+ try {
+ ParcelFileDescriptor dup = aidlModel.data.dup();
+ fd.setInt$(dup.detachFd());
+ hidlModel.data = HidlMemoryUtil.fileDescriptorToHidlMemory(fd, aidlModel.dataSize);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
return hidlModel;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e8e4059af324..a9f06813faf5 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -700,11 +700,15 @@ class ActivityStarter {
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
}
+ // The original options may have additional info about metrics. The mOptions is not
+ // used here because it may be cleared in setTargetStackIfNeeded.
+ final ActivityOptions originalOptions = mRequest.activityOptions != null
+ ? mRequest.activityOptions.getOriginalOptions() : null;
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
- mLastStartActivityRecord, mOptions);
+ mLastStartActivityRecord, originalOptions);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));
}
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 6305fda4924c..958a7a8f07f8 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -16,9 +16,13 @@
package com.android.server.wm;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
+
import android.util.ArrayMap;
import android.util.ArraySet;
+import com.android.internal.protolog.common.ProtoLog;
+
import java.util.Set;
/**
@@ -63,25 +67,38 @@ class BLASTSyncEngine {
private void tryFinish() {
if (mRemainingTransactions == 0 && mReady) {
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Finished. Reporting %d "
+ + "containers to %s", BLASTSyncEngine.this.hashCode(), mSyncId,
+ mWindowContainersReady.size(), mListener);
mListener.onTransactionReady(mSyncId, mWindowContainersReady);
mPendingSyncs.remove(mSyncId);
}
}
- public void onTransactionReady(int mSyncId, Set<WindowContainer> windowContainersReady) {
+ public void onTransactionReady(int syncId, Set<WindowContainer> windowContainersReady) {
mRemainingTransactions--;
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Child ready, now ready=%b"
+ + " and waiting on %d transactions", BLASTSyncEngine.this.hashCode(), mSyncId,
+ mReady, mRemainingTransactions);
mWindowContainersReady.addAll(windowContainersReady);
tryFinish();
}
void setReady() {
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Set ready",
+ BLASTSyncEngine.this.hashCode(), mSyncId);
mReady = true;
tryFinish();
}
boolean addToSync(WindowContainer wc) {
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Trying to add %s",
+ BLASTSyncEngine.this.hashCode(), mSyncId, wc);
if (wc.prepareForSync(this, mSyncId)) {
mRemainingTransactions++;
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Added %s. now waiting "
+ + "on %d transactions", BLASTSyncEngine.this.hashCode(), mSyncId, wc,
+ mRemainingTransactions);
return true;
}
return false;
@@ -105,6 +122,7 @@ class BLASTSyncEngine {
final int id = mNextSyncId++;
final SyncState s = new SyncState(listener, id);
mPendingSyncs.put(id, s);
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncSet{%x:%d} Start for %s", hashCode(), id, listener);
return id;
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 572c9b306047..6fffde14cf7d 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -649,7 +649,7 @@ public class DisplayPolicy {
mRefreshRatePolicy = new RefreshRatePolicy(mService,
mDisplayContent.getDisplayInfo(),
- mService.mHighRefreshRateBlacklist);
+ mService.mHighRefreshRateDenylist);
mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
mContext, () -> {
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
index aac6b2544c4f..cdc14cd11228 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateDenylist.java
@@ -34,62 +34,62 @@ import java.io.PrintWriter;
/**
* A Denylist for packages that should force the display out of high refresh rate.
*/
-class HighRefreshRateBlacklist {
+class HighRefreshRateDenylist {
- private final ArraySet<String> mBlacklistedPackages = new ArraySet<>();
+ private final ArraySet<String> mDenylistedPackages = new ArraySet<>();
@NonNull
- private final String[] mDefaultBlacklist;
+ private final String[] mDefaultDenylist;
private final Object mLock = new Object();
private DeviceConfigInterface mDeviceConfig;
private OnPropertiesChangedListener mListener = new OnPropertiesChangedListener();
- static HighRefreshRateBlacklist create(@NonNull Resources r) {
- return new HighRefreshRateBlacklist(r, DeviceConfigInterface.REAL);
+ static HighRefreshRateDenylist create(@NonNull Resources r) {
+ return new HighRefreshRateDenylist(r, DeviceConfigInterface.REAL);
}
@VisibleForTesting
- HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) {
- mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
+ HighRefreshRateDenylist(Resources r, DeviceConfigInterface deviceConfig) {
+ mDefaultDenylist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
mDeviceConfig = deviceConfig;
mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
BackgroundThread.getExecutor(), mListener);
final String property = mDeviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
KEY_HIGH_REFRESH_RATE_BLACKLIST);
- updateBlacklist(property);
+ updateDenylist(property);
}
- private void updateBlacklist(@Nullable String property) {
+ private void updateDenylist(@Nullable String property) {
synchronized (mLock) {
- mBlacklistedPackages.clear();
+ mDenylistedPackages.clear();
if (property != null) {
String[] packages = property.split(",");
for (String pkg : packages) {
String pkgName = pkg.trim();
if (!pkgName.isEmpty()) {
- mBlacklistedPackages.add(pkgName);
+ mDenylistedPackages.add(pkgName);
}
}
} else {
// If there's no config, or the config has been deleted, fallback to the device's
// default denylist
- for (String pkg : mDefaultBlacklist) {
- mBlacklistedPackages.add(pkg);
+ for (String pkg : mDefaultDenylist) {
+ mDenylistedPackages.add(pkg);
}
}
}
}
- boolean isBlacklisted(String packageName) {
+ boolean isDenylisted(String packageName) {
synchronized (mLock) {
- return mBlacklistedPackages.contains(packageName);
+ return mDenylistedPackages.contains(packageName);
}
}
void dump(PrintWriter pw) {
- pw.println("High Refresh Rate Blacklist");
+ pw.println("High Refresh Rate Denylist");
pw.println(" Packages:");
synchronized (mLock) {
- for (String pkg : mBlacklistedPackages) {
+ for (String pkg : mDenylistedPackages) {
pw.println(" " + pkg);
}
}
@@ -100,13 +100,13 @@ class HighRefreshRateBlacklist {
void dispose() {
mDeviceConfig.removeOnPropertiesChangedListener(mListener);
mDeviceConfig = null;
- mBlacklistedPackages.clear();
+ mDenylistedPackages.clear();
}
private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) {
- updateBlacklist(
+ updateDenylist(
properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/));
}
}
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index 072116f04aac..91014aa69831 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -30,7 +30,7 @@ class RefreshRatePolicy {
private final int mLowRefreshRateId;
private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>();
- private final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
+ private final HighRefreshRateDenylist mHighRefreshRateDenylist;
private final WindowManagerService mWmService;
/**
@@ -55,9 +55,9 @@ class RefreshRatePolicy {
static final int LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo,
- HighRefreshRateBlacklist blacklist) {
+ HighRefreshRateDenylist denylist) {
mLowRefreshRateId = findLowRefreshRateModeId(displayInfo);
- mHighRefreshRateBlacklist = blacklist;
+ mHighRefreshRateDenylist = denylist;
mWmService = wmService;
}
@@ -108,7 +108,7 @@ class RefreshRatePolicy {
}
// If app is denylisted using higher refresh rate, return default (lower) refresh rate
- if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) {
+ if (mHighRefreshRateDenylist.isDenylisted(packageName)) {
return mLowRefreshRateId;
}
return 0;
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index ede6708d5f8f..9205401ed2ee 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -150,6 +150,14 @@ public class SafeActivityOptions {
}
/**
+ * Gets the original options passed in. It should only be used for logging. DO NOT use it as a
+ * condition in the logic of activity launch.
+ */
+ ActivityOptions getOriginalOptions() {
+ return mOriginalOptions;
+ }
+
+ /**
* @see ActivityOptions#popAppVerificationBundle
*/
Bundle popAppVerificationBundle() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ae8f7a556ffd..2b93080a8dad 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -32,6 +32,7 @@ import static android.view.SurfaceControl.Transaction;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.AppTransition.MAX_APP_TRANSITION_DURATION;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -2886,6 +2887,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
// If we are invisible, no need to sync, likewise if we are already engaged in a sync,
// we can't support overlapping syncs on a single container yet.
if (!isVisible() || mWaitingListener != null) {
+ ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "- NOT adding to sync: visible=%b "
+ + "hasListener=%b", isVisible(), mWaitingListener != null);
return false;
}
mUsingBLASTSyncTransaction = true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8c2619d75201..a680213c52a7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1005,7 +1005,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Configuration mTempConfiguration = new Configuration();
- final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
+ final HighRefreshRateDenylist mHighRefreshRateDenylist;
// If true, only the core apps and services are being launched because the device
// is in a special boot mode, such as being encrypted or waiting for a decryption password.
@@ -1302,7 +1302,7 @@ public class WindowManagerService extends IWindowManager.Stub
this, mInputManager, mActivityTaskManager, mH.getLooper());
mDragDropController = new DragDropController(this, mH.getLooper());
- mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
+ mHighRefreshRateDenylist = HighRefreshRateDenylist.create(context.getResources());
mConstants = new WindowManagerConstants(this, DeviceConfigInterface.REAL);
mConstants.start(new HandlerExecutor(mH));
@@ -5939,7 +5939,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void dumpHighRefreshRateBlacklist(PrintWriter pw) {
pw.println("WINDOW MANAGER HIGH REFRESH RATE BLACKLIST (dumpsys window refresh)");
- mHighRefreshRateBlacklist.dump(pw);
+ mHighRefreshRateDenylist.dump(pw);
}
private void dumpTraceStatus(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 67d230aae0fb..59f209aca6ba 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -41,7 +41,6 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
-
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -465,8 +464,10 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
* Allows background activity starts using token {@code entity}. Optionally, you can provide
* {@code originatingToken} if you have one such originating token, this is useful for tracing
* back the grant in the case of the notification token.
+ *
+ * If {@code entity} is already added, this method will update its {@code originatingToken}.
*/
- public void addAllowBackgroundActivityStartsToken(Binder entity,
+ public void addOrUpdateAllowBackgroundActivityStartsToken(Binder entity,
@Nullable IBinder originatingToken) {
synchronized (mAtm.mGlobalLock) {
mBackgroundActivityStartTokens.put(entity, originatingToken);
@@ -475,7 +476,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/**
* Removes token {@code entity} that allowed background activity starts added via {@link
- * #addAllowBackgroundActivityStartsToken(Binder, IBinder)}.
+ * #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}.
*/
public void removeAllowBackgroundActivityStartsToken(Binder entity) {
synchronized (mAtm.mGlobalLock) {
@@ -485,7 +486,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/**
* Returns true if background activity starts are allowed by any token added via {@link
- * #addAllowBackgroundActivityStartsToken(Binder, IBinder)}.
+ * #addOrUpdateAllowBackgroundActivityStartsToken(Binder, IBinder)}.
*/
public boolean areBackgroundActivityStartsAllowedByToken() {
synchronized (mAtm.mGlobalLock) {
@@ -1575,10 +1576,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
}
if (mBackgroundActivityStartTokens.size() > 0) {
- pw.print(prefix); pw.println("Background activity start tokens:");
+ pw.print(prefix);
+ pw.println("Background activity start tokens (token: originating token):");
for (int i = 0; i < mBackgroundActivityStartTokens.size(); i++) {
pw.print(prefix); pw.print(" - ");
- pw.println(mBackgroundActivityStartTokens.keyAt(i));
+ pw.print(mBackgroundActivityStartTokens.keyAt(i));
+ pw.print(": ");
+ pw.println(mBackgroundActivityStartTokens.valueAt(i));
+
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5e814005a5e2..029c158814b3 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -441,10 +441,6 @@ class WindowStateAnimator {
return mSurfaceController;
}
- if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
- windowType = SurfaceControl.WINDOW_TYPE_DONT_SCREENSHOT;
- }
-
w.setHasSurface(false);
if (DEBUG_ANIM) {
@@ -462,6 +458,10 @@ class WindowStateAnimator {
flags |= SurfaceControl.SECURE;
}
+ if ((mWin.mAttrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0) {
+ flags |= SurfaceControl.SKIP_SCREENSHOT;
+ }
+
calculateSurfaceBounds(w, attrs, mTmpSize);
final int width = mTmpSize.width();
final int height = mTmpSize.height();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
index 5193fa85d238..b6b4d8a04cb6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
@@ -58,4 +58,12 @@ class CallerIdentity {
@Nullable public ComponentName getComponentName() {
return mComponentName;
}
+
+ public boolean hasAdminComponent() {
+ return mComponentName != null;
+ }
+
+ public boolean hasPackage() {
+ return mPackageName != null;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 183a1495b075..8f1fb127ec17 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1567,6 +1567,54 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
/**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
+ * component name is provided, look up the component name and fill it in for the caller.
+ */
+ private CallerIdentity getCallerIdentityOptionalAdmin(@Nullable ComponentName adminComponent) {
+ if (adminComponent == null) {
+ ActiveAdmin admin = getActiveAdminOfCaller();
+ if (admin != null) {
+ return getCallerIdentity(admin.info.getComponent());
+ }
+ throw new SecurityException("Caller is not an active admin");
+ } else {
+ return getCallerIdentity(adminComponent);
+ }
+ }
+
+ /**
+ * Creates a new {@link CallerIdentity} object to represent the caller's identity. If no
+ * package name is provided, look up the package name and fill it in for the caller.
+ */
+ private CallerIdentity getCallerIdentityOptionalPackage(@Nullable String callerPackage) {
+ if (callerPackage == null) {
+ ActiveAdmin admin = getActiveAdminOfCaller();
+ if (admin != null) {
+ return getCallerIdentity(admin.info.getPackageName());
+ }
+ throw new SecurityException("Caller is not an active admin");
+ } else {
+ return getCallerIdentity(callerPackage);
+ }
+ }
+
+ /**
+ * Retrieves the active admin of the caller. This method should not be called directly and
+ * should only be called by {@link #getCallerIdentityOptionalAdmin} or
+ * {@link #getCallerIdentityOptionalPackage}.
+ */
+ private ActiveAdmin getActiveAdminOfCaller() {
+ final int callerUid = mInjector.binderGetCallingUid();
+ final DevicePolicyData policy = getUserData(UserHandle.getUserId(callerUid));
+ for (ActiveAdmin admin : policy.mAdminList) {
+ if (admin.getUid() == callerUid) {
+ return admin;
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks if the device is in COMP mode, and if so migrates it to managed profile on a
* corporate owned device.
*/
@@ -3071,7 +3119,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = getCallerIdentity(adminReceiver);
+ final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
@@ -3630,6 +3678,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean addCrossProfileWidgetProvider(ComponentName admin, String packageName) {
+ Objects.requireNonNull(admin, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
List<String> changedProviders = null;
@@ -3663,6 +3713,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean removeCrossProfileWidgetProvider(ComponentName admin, String packageName) {
+ Objects.requireNonNull(admin, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
List<String> changedProviders = null;
@@ -3696,6 +3748,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<String> getCrossProfileWidgetProviders(ComponentName admin) {
+ Objects.requireNonNull(admin, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(isProfileOwner(caller) || isDeviceOwner(caller));
@@ -4833,8 +4887,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
byte[] cert, byte[] chain, String alias, boolean requestAccess,
boolean isUserSelectable) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
final long id = mInjector.binderClearCallingIdentity();
try {
@@ -4872,8 +4927,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean removeKeyPair(ComponentName who, String callerPackage, String alias) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
final long id = Binder.clearCallingIdentity();
try {
@@ -4908,8 +4964,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkStringNotEmpty(packageName, "Package to grant to cannot be empty");
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
final int granteeUid;
try {
@@ -5052,8 +5109,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
enforceCallerCanRequestDeviceIdAttestation(caller);
enforceIndividualAttestationSupportedIfRequested(attestationUtilsFlags);
} else {
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
}
// As the caller will be granted access to the key, ensure no UID was specified, as
@@ -5147,8 +5205,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean setKeyPairCertificate(ComponentName who, String callerPackage, String alias,
byte[] cert, byte[] chain, boolean isUserSelectable) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isProfileOwner(caller) || isCallerDelegate(caller, DELEGATION_CERT_INSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_CERT_INSTALL)));
final long id = mInjector.binderClearCallingIdentity();
try (final KeyChainConnection keyChainConnection =
@@ -5613,6 +5672,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown,
List<String> lockdownWhitelist)
throws SecurityException {
+ Objects.requireNonNull(who, "ComponentName is null");
+
enforceProfileOrDeviceOwner(who);
final CallerIdentity caller = getCallerIdentity(who);
@@ -5752,16 +5813,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
final CallerIdentity caller = getCallerIdentity();
boolean calledByProfileOwnerOnOrgOwnedDevice =
- isProfileOwnerOfOrganizationOwnedDevice(caller);
+ isProfileOwnerOfOrganizationOwnedDevice(caller.getUserId());
if (calledOnParentInstance) {
Preconditions.checkCallAuthorization(calledByProfileOwnerOnOrgOwnedDevice,
"Wiping the entire device can only be done by a profile owner on "
+ "organization-owned device.");
}
if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
- Preconditions.checkCallAuthorization(
- isDeviceOwner(caller) || calledByProfileOwnerOnOrgOwnedDevice,
- "Only device owners or proflie owners of organization-owned device can set "
+ Preconditions.checkCallAuthorization(isCallerDeviceOwner(caller.getUid())
+ || calledByProfileOwnerOnOrgOwnedDevice,
+ "Only device owners or profile owners of organization-owned device can set "
+ "WIPE_RESET_PROTECTION_DATA");
}
@@ -5960,9 +6021,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = comp != null
- ? getCallerIdentity(comp)
- : getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentityOptionalAdmin(comp);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(BIND_DEVICE_ADMIN));
@@ -6399,9 +6458,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = who != null
- ? getCallerIdentity(who)
- : getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentityOptionalAdmin(who);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
@@ -6435,9 +6492,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = callerPackage != null
- ? getCallerIdentity(callerPackage)
- : getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentityOptionalPackage(callerPackage);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
// It's not critical here, but let's make sure the package name is correct, in case
@@ -6546,9 +6601,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
if (parent) {
- Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(
- isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity(who)));
+ isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity().getUserId()));
}
synchronized (getLockObject()) {
@@ -6934,9 +6988,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
if (parent) {
- Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(
- isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity(who)));
+ isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity().getUserId()));
}
synchronized (getLockObject()) {
@@ -7070,8 +7123,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
Objects.requireNonNull(packageList, "packageList is null");
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
+ || (caller.hasPackage()
+ && isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES)));
synchronized (getLockObject()) {
// Get the device owner
@@ -7097,8 +7151,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
+ || (caller.hasPackage()
+ && isCallerDelegate(caller, DELEGATION_KEEP_UNINSTALLED_PACKAGES)));
// TODO In split system user mode, allow apps on user 0 to query the list
synchronized (getLockObject()) {
@@ -8517,8 +8572,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void setApplicationRestrictions(ComponentName who, String callerPackage,
String packageName, Bundle settings) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS)));
mInjector.binderWithCleanCallingIdentity(() -> {
mUserManager.setApplicationRestrictions(packageName, settings,
@@ -8558,9 +8614,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(agent, "agent null");
Preconditions.checkArgumentNonnegative(userHandle, "Invalid userId");
- final CallerIdentity caller = admin != null
- ? getCallerIdentity(admin)
- : getCallerIdentity();
+ final CallerIdentity caller = getCallerIdentityOptionalAdmin(admin);
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
synchronized (getLockObject()) {
@@ -9442,8 +9496,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public Bundle getApplicationRestrictions(ComponentName who, String callerPackage,
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS)));
return mInjector.binderWithCleanCallingIdentity(() -> {
Bundle bundle = mUserManager.getApplicationRestrictions(packageName,
@@ -9458,8 +9513,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public String[] setPackagesSuspended(ComponentName who, String callerPackage,
String[] packageNames, boolean suspended) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
String[] result = null;
synchronized (getLockObject()) {
@@ -9489,8 +9545,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public boolean isPackageSuspended(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
synchronized (getLockObject()) {
long id = mInjector.binderClearCallingIdentity();
@@ -9650,8 +9707,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean setApplicationHidden(ComponentName who, String callerPackage, String packageName,
boolean hidden, boolean parent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
boolean result;
@@ -9682,8 +9740,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean isApplicationHidden(ComponentName who, String callerPackage,
String packageName, boolean parent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PACKAGE_ACCESS)));
final int userId = parent ? getProfileParentId(caller.getUserId()) : caller.getUserId();
synchronized (getLockObject()) {
@@ -9716,8 +9775,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void enableSystemApp(ComponentName who, String callerPackage, String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP)));
synchronized (getLockObject()) {
final boolean isDemo = isCurrentUserDemo();
@@ -9759,8 +9819,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public int enableSystemAppWithIntent(ComponentName who, String callerPackage, Intent intent) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_ENABLE_SYSTEM_APP)));
int numberOfAppsInstalled = 0;
synchronized (getLockObject()) {
@@ -9827,8 +9888,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean installExistingPackage(ComponentName who, String callerPackage,
String packageName) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_INSTALL_EXISTING_PACKAGE));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage()
+ && isCallerDelegate(caller, DELEGATION_INSTALL_EXISTING_PACKAGE)));
boolean result;
synchronized (getLockObject()) {
@@ -9941,8 +10004,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void setUninstallBlocked(ComponentName who, String callerPackage, String packageName,
boolean uninstallBlocked) {
final CallerIdentity caller = getCallerIdentity(who, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_BLOCK_UNINSTALL)));
final int userId = caller.getUserId();
synchronized (getLockObject()) {
@@ -10489,6 +10553,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
@@ -11596,8 +11662,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setPermissionPolicy(ComponentName admin, String callerPackage, int policy) {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
synchronized (getLockObject()) {
DevicePolicyData userPolicy = getUserData(caller.getUserId());
@@ -11630,8 +11697,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Objects.requireNonNull(callback);
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
synchronized (getLockObject()) {
long ident = mInjector.binderClearCallingIdentity();
@@ -11694,9 +11762,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public int getPermissionGrantState(ComponentName admin, String callerPackage,
String packageName, String permission) throws RemoteException {
final CallerIdentity caller = getCallerIdentity(admin, callerPackage);
- Preconditions.checkCallAuthorization(
- isSystemUid(caller) || isDeviceOwner(caller) || isProfileOwner(caller)
- || isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT));
+ Preconditions.checkCallAuthorization(isSystemUid(caller) || (caller.hasAdminComponent()
+ && (isProfileOwner(caller) || isDeviceOwner(caller)))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_PERMISSION_GRANT)));
synchronized (getLockObject()) {
return mInjector.binderWithCleanCallingIdentity(() -> {
@@ -13149,8 +13217,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
final CallerIdentity caller = getCallerIdentity(admin, packageName);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)));
synchronized (getLockObject()) {
if (enabled == isNetworkLoggingEnabledInternalLocked()) {
@@ -13267,9 +13335,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
final CallerIdentity caller = getCallerIdentity(admin, packageName);
- Preconditions.checkCallAuthorization(
- isDeviceOwner(caller) || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)
- || hasCallingOrSelfPermission(permission.MANAGE_USERS));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING))
+ || hasCallingOrSelfPermission(permission.MANAGE_USERS));
synchronized (getLockObject()) {
return isNetworkLoggingEnabledInternalLocked();
@@ -13295,8 +13363,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return null;
}
final CallerIdentity caller = getCallerIdentity(admin, packageName);
- Preconditions.checkCallAuthorization(isDeviceOwner(caller)
- || isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING));
+ Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller))
+ || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)));
Preconditions.checkCallAuthorization(areAllUsersAffiliatedWithDeviceLocked());
synchronized (getLockObject()) {
@@ -14494,6 +14562,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public List<String> getUserControlDisabledPackages(ComponentName who) {
+ Objects.requireNonNull(who, "ComponentName is null");
+
final CallerIdentity caller = getCallerIdentity(who);
Preconditions.checkCallAuthorization(isDeviceOwner(caller));
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 44a07a17824f..e8bf468f032e 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -308,6 +308,7 @@ IncrementalService::~IncrementalService() {
}
mJobCondition.notify_all();
mJobProcessor.join();
+ mLooper->wake();
mCmdLooperThread.join();
mTimedQueue->stop();
mProgressUpdateJobQueue->stop();
@@ -1386,7 +1387,7 @@ bool IncrementalService::mountExistingImage(std::string_view root) {
}
void IncrementalService::runCmdLooper() {
- constexpr auto kTimeoutMsecs = 1000;
+ constexpr auto kTimeoutMsecs = -1;
while (mRunning.load(std::memory_order_relaxed)) {
mLooper->pollAll(kTimeoutMsecs);
}
diff --git a/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
new file mode 100644
index 000000000000..488e5cdf33b9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/BatteryStatsServiceTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BatteryStatsImpl;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@RunWith(AndroidJUnit4.class)
+public final class BatteryStatsServiceTest {
+
+ private BatteryStatsService mBatteryStatsService;
+ private HandlerThread mBgThread;
+
+ @Before
+ public void setUp() {
+ final Context context = InstrumentationRegistry.getContext();
+ mBgThread = new HandlerThread("bg thread");
+ mBgThread.start();
+ mBatteryStatsService = new BatteryStatsService(context,
+ context.getCacheDir(), new Handler(mBgThread.getLooper()));
+ }
+
+ @After
+ public void tearDown() {
+ mBatteryStatsService.shutdown();
+ mBgThread.quitSafely();
+ }
+
+ @Test
+ public void testAwaitCompletion() throws Exception {
+ final CountDownLatch readyLatch = new CountDownLatch(2);
+ final CountDownLatch startLatch = new CountDownLatch(1);
+ final CountDownLatch testLatch = new CountDownLatch(1);
+ final AtomicBoolean quiting = new AtomicBoolean(false);
+ final AtomicBoolean finished = new AtomicBoolean(false);
+ final int uid = Process.myUid();
+ final Thread noteThread = new Thread(() -> {
+ final int maxIterations = 1000;
+ final int eventCode = 12345;
+ final String eventName = "placeholder";
+ final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+
+ readyLatch.countDown();
+ try {
+ startLatch.await();
+ } catch (InterruptedException e) {
+ }
+
+ for (int i = 0; i < maxIterations && !quiting.get(); i++) {
+ synchronized (stats) {
+ mBatteryStatsService.noteEvent(eventCode, eventName, uid);
+ }
+ }
+ finished.set(true);
+ });
+ final Thread waitThread = new Thread(() -> {
+ readyLatch.countDown();
+ try {
+ startLatch.await();
+ } catch (InterruptedException e) {
+ }
+
+ do {
+ mBatteryStatsService.takeUidSnapshot(uid);
+ } while (!finished.get() && !quiting.get());
+
+ if (!quiting.get()) {
+ // do one more to ensure we've cleared the queue
+ mBatteryStatsService.takeUidSnapshot(uid);
+ }
+
+ testLatch.countDown();
+ });
+ noteThread.start();
+ waitThread.start();
+ readyLatch.await();
+ startLatch.countDown();
+
+ try {
+ assertTrue("Timed out in waiting for the completion of battery event handling",
+ testLatch.await(10 * 1000, TimeUnit.MILLISECONDS));
+ } finally {
+ quiting.set(true);
+ noteThread.interrupt();
+ noteThread.join(1000);
+ waitThread.interrupt();
+ waitThread.join(1000);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
index dd4c0814a441..c60d5fb95846 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -95,14 +95,14 @@ public class HdmiCecControllerTest {
/** Tests for {@link HdmiCecController#allocateLogicalAddress} */
@Test
- public void testAllocatLogicalAddress_TvDevicePreferredNotOcupied() {
+ public void testAllocateLogicalAddress_TvDevicePreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_TV, mCallback);
mTestLooper.dispatchAll();
assertEquals(ADDR_TV, mLogicalAddress);
}
@Test
- public void testAllocatLogicalAddress_TvDeviceNonPreferredNotOcupied() {
+ public void testAllocateLogicalAddress_TvDeviceNonPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
mTestLooper.dispatchAll();
@@ -110,7 +110,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_TvDeviceNonPreferredFirstOcupied() {
+ public void testAllocateLogicalAddress_TvDeviceNonPreferredFirstOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_TV, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
mTestLooper.dispatchAll();
@@ -118,7 +118,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_TvDeviceNonPreferredAllOcupied() {
+ public void testAllocateLogicalAddress_TvDeviceNonPreferredAllOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_TV, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_SPECIFIC_USE, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
@@ -127,7 +127,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_AudioSystemNonPreferredNotOcupied() {
+ public void testAllocateLogicalAddress_AudioSystemNonPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(
DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
mTestLooper.dispatchAll();
@@ -135,7 +135,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_AudioSystemNonPreferredAllOcupied() {
+ public void testAllocateLogicalAddress_AudioSystemNonPreferredAllOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_AUDIO_SYSTEM, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(
DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
@@ -144,14 +144,14 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
+ public void testAllocateLogicalAddress_PlaybackPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
mTestLooper.dispatchAll();
assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
}
@Test
- public void testAllocatLogicalAddress_PlaybackPreferredOcuppied() {
+ public void testAllocateLogicalAddress_PlaybackPreferredOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
mTestLooper.dispatchAll();
@@ -159,14 +159,14 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
+ public void testAllocateLogicalAddress_PlaybackNoPreferredNotOccupied() {
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
mTestLooper.dispatchAll();
assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
}
@Test
- public void testAllocatLogicalAddress_PlaybackNoPreferredFirstOcuppied() {
+ public void testAllocateLogicalAddress_PlaybackNoPreferredFirstOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
mTestLooper.dispatchAll();
@@ -174,7 +174,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_PlaybackNonPreferredFirstTwoOcuppied() {
+ public void testAllocateLogicalAddress_PlaybackNonPreferredFirstTwoOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
@@ -183,7 +183,7 @@ public class HdmiCecControllerTest {
}
@Test
- public void testAllocatLogicalAddress_PlaybackNonPreferredAllOcupied() {
+ public void testAllocateLogicalAddress_PlaybackNonPreferredAllOccupied() {
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_1, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_2, SendMessageResult.SUCCESS);
mNativeWrapper.setPollAddressResponse(ADDR_PLAYBACK_3, SendMessageResult.SUCCESS);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index dac05424e01f..bc747832e253 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -62,6 +62,7 @@ import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.PermissionSettings;
import com.google.common.truth.Truth;
@@ -94,6 +95,8 @@ public class PackageManagerSettingsTests {
PermissionSettings mPermissionSettings;
@Mock
RuntimePermissionsPersistence mRuntimePermissionsPersistence;
+ @Mock
+ LegacyPermissionDataProvider mPermissionDataProvider;
@Before
public void initializeMocks() {
@@ -115,7 +118,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}
@@ -129,7 +132,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// write out, read back in and verify the same
@@ -145,7 +148,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
@@ -167,13 +170,13 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
settings.writeLPr();
// Create Settings again to make it read from the new files
settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
@@ -196,7 +199,8 @@ public class PackageManagerSettingsTests {
writePackageRestrictions_noSuspendingPackageXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
+ lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -219,7 +223,8 @@ public class PackageManagerSettingsTests {
writePackageRestrictions_noSuspendParamsMapXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
+ lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -246,7 +251,7 @@ public class PackageManagerSettingsTests {
@Test
public void testReadWritePackageRestrictions_suspendInfo() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
@@ -344,7 +349,7 @@ public class PackageManagerSettingsTests {
@Test
public void testReadWritePackageRestrictions_distractionFlags() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, null,
new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
@@ -389,7 +394,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getTargetContext();
final Object lock = new Object();
final Settings settingsUnderTest = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
ps1.appId = Process.FIRST_APPLICATION_UID;
ps1.pkg = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME_1).hideAsParsed())
@@ -465,7 +470,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// Enable/Disable a package
@@ -638,7 +643,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 =
@@ -748,7 +753,7 @@ public class PackageManagerSettingsTests {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
- mRuntimePermissionsPersistence, lock);
+ mRuntimePermissionsPersistence, mPermissionDataProvider, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 = Settings.createNewSetting(
diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
index ebcf10dd019f..509eb2563376 100644
--- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareImplTest.java
@@ -59,6 +59,7 @@ import android.os.HidlMemoryUtil;
import android.os.HwParcel;
import android.os.IHwBinder;
import android.os.IHwInterface;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.system.ErrnoException;
@@ -126,7 +127,7 @@ public class SoundTriggerMiddlewareImplTest {
model.uuid = "12345678-2345-3456-4567-abcdef987654";
model.vendorUuid = "87654321-5432-6543-7654-456789fedcba";
byte[] data = new byte[]{91, 92, 93, 94, 95};
- model.data = byteArrayToFileDescriptor(data);
+ model.data = new ParcelFileDescriptor(byteArrayToFileDescriptor(data));
model.dataSize = data.length;
return model;
}
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 9e7226e7cacf..1a4b119a6c99 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -69,6 +69,7 @@ import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
@@ -102,10 +103,12 @@ import android.app.StatsManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -282,6 +285,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationHistoryManager mHistoryManager;
@Mock
StatsManager mStatsManager;
+ BroadcastReceiver mPackageIntentReceiver;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@@ -480,6 +484,28 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
+ // Capture PackageIntentReceiver
+ ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ ArgumentCaptor<IntentFilter> intentFilterCaptor =
+ ArgumentCaptor.forClass(IntentFilter.class);
+
+ verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
+ any(), intentFilterCaptor.capture(), any(), any());
+ List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
+ List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
+
+ for (int i = 0; i < intentFilters.size(); i++) {
+ final IntentFilter filter = intentFilters.get(i);
+ if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
+ && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
+ && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
+ mPackageIntentReceiver = broadcastReceivers.get(i);
+ break;
+ }
+ }
+ assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
+
// Pretend the shortcut exists
List<ShortcutInfo> shortcutInfos = new ArrayList<>();
ShortcutInfo info = mock(ShortcutInfo.class);
@@ -526,7 +552,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void tearDown() throws Exception {
if (mFile != null) mFile.delete();
clearDeviceConfig();
- mService.unregisterDeviceConfigChange();
+
+ try {
+ mService.onDestroy();
+ } catch (IllegalStateException e) {
+ // can throw if a broadcast receiver was never registered
+ }
+
InstrumentationRegistry.getInstrumentation()
.getUiAutomation().dropShellPermissionIdentity();
}
@@ -2533,10 +2565,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testHasCompanionDevice_noService() {
- mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
+ NotificationManagerService noManService =
+ new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
mNotificationInstanceIdSequence);
- assertFalse(mService.hasCompanionDevice(mListener));
+ assertFalse(noManService.hasCompanionDevice(mListener));
}
@Test
@@ -4347,13 +4380,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(notif2);
// on broadcast, hide the 2 notifications
- mService.simulatePackageSuspendBroadcast(true, PKG);
+ simulatePackageSuspendBroadcast(true, PKG, notif1.getUid());
ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
assertEquals(2, captorHide.getValue().size());
// on broadcast, unhide the 2 notifications
- mService.simulatePackageSuspendBroadcast(false, PKG);
+ simulatePackageSuspendBroadcast(false, PKG, notif1.getUid());
ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
assertEquals(2, captorUnhide.getValue().size());
@@ -4370,7 +4403,24 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(notif2);
// on broadcast, nothing is hidden since no notifications are of package "test_package"
- mService.simulatePackageSuspendBroadcast(true, "test_package");
+ simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid());
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
+ assertEquals(0, captor.getValue().size());
+ }
+
+ @Test
+ public void testNotificationFromDifferentUserHidden() {
+ // post 2 notification from this package
+ final NotificationRecord notif1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ final NotificationRecord notif2 = generateNotificationRecord(
+ mTestNotificationChannel, 2, null, false);
+ mService.addNotification(notif1);
+ mService.addNotification(notif2);
+
+ // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG
+ simulatePackageSuspendBroadcast(true, PKG, 10);
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
assertEquals(0, captor.getValue().size());
@@ -4387,16 +4437,18 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(pkgB);
// on broadcast, hide one of the packages
- mService.simulatePackageDistractionBroadcast(
- PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"});
+ simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"},
+ new int[] {1000});
ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
assertEquals(1, captorHide.getValue().size());
assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName());
// on broadcast, unhide the package
- mService.simulatePackageDistractionBroadcast(
- PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"});
+ simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"},
+ new int[] {1000});
ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
assertEquals(1, captorUnhide.getValue().size());
@@ -4414,8 +4466,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(pkgB);
// on broadcast, hide one of the packages
- mService.simulatePackageDistractionBroadcast(
- PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"});
+ simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"},
+ new int[] {1000, 1001});
ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
// should be called only once.
@@ -4425,8 +4478,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName());
// on broadcast, unhide the package
- mService.simulatePackageDistractionBroadcast(
- PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"});
+ simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"},
+ new int[] {1000, 1001});
ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
// should be called only once.
@@ -4444,8 +4498,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(notif1);
// on broadcast, nothing is hidden since no notifications are of package "test_package"
- mService.simulatePackageDistractionBroadcast(
- PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"});
+ simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"},
+ new int[]{notif1.getUid()});
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
assertEquals(0, captor.getValue().size());
@@ -7011,4 +7066,34 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertTrue(mService.isVisibleToListener(sbn, info));
}
+ private void simulatePackageSuspendBroadcast(boolean suspend, String pkg,
+ int uid) {
+ // mimics receive broadcast that package is (un)suspended
+ // but does not actually (un)suspend the package
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
+ new String[]{pkg});
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid});
+
+ final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
+ : Intent.ACTION_PACKAGES_UNSUSPENDED;
+ final Intent intent = new Intent(action);
+ intent.putExtras(extras);
+
+ mPackageIntentReceiver.onReceive(getContext(), intent);
+ }
+
+ private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) {
+ // mimics receive broadcast that package is (un)distracting
+ // but does not actually register that info with packagemanager
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids);
+
+ final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
+ intent.putExtras(extras);
+
+ mPackageIntentReceiver.onReceive(getContext(), intent);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 076047b35604..e47881917b2c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -63,6 +63,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -670,7 +671,7 @@ public class ActivityStarterTests extends WindowTestsBase {
doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
// caller is temp allowed
if (callerIsTempAllowed) {
- callerApp.addAllowBackgroundActivityStartsToken(new Binder(), null);
+ callerApp.addOrUpdateAllowBackgroundActivityStartsToken(new Binder(), null);
}
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
@@ -800,6 +801,7 @@ public class ActivityStarterTests extends WindowTestsBase {
final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
new ActivityBuilder(mAtm).setTask(topTask).build();
+ doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger();
// Start activity with the same intent as {@code singleTaskActivity} on secondary display.
final ActivityOptions options = ActivityOptions.makeBasic()
.setLaunchDisplayId(secondaryDisplay.mDisplayId);
@@ -813,6 +815,9 @@ public class ActivityStarterTests extends WindowTestsBase {
// Ensure secondary display only creates two stacks.
verify(secondaryTaskContainer, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
+ // The metrics logger should receive the same result and non-null options.
+ verify(mActivityMetricsLogger).notifyActivityLaunched(any() /* launchingState */,
+ eq(result), eq(singleTaskActivity), notNull() /* options */);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
index f53894ad9ec5..c3e1922a09cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateDenylistTest.java
@@ -40,107 +40,107 @@ import java.util.concurrent.Executor;
/**
* Build/Install/Run:
- * atest WmTests:HighRefreshRateBlacklistTest
+ * atest WmTests:HighRefreshRateDenylistTest
*/
@SmallTest
@Presubmit
-public class HighRefreshRateBlacklistTest {
+public class HighRefreshRateDenylistTest {
private static final String APP1 = "com.android.sample1";
private static final String APP2 = "com.android.sample2";
private static final String APP3 = "com.android.sample3";
- private HighRefreshRateBlacklist mBlacklist;
+ private HighRefreshRateDenylist mDenylist;
@After
public void tearDown() {
- mBlacklist.dispose();
+ mDenylist.dispose();
}
@Test
- public void testDefaultBlacklist() {
+ public void testDefaultDenylist() {
final Resources r = createResources(APP1, APP2);
- mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig());
+ mDenylist = new HighRefreshRateDenylist(r, new FakeDeviceConfig());
- assertTrue(mBlacklist.isBlacklisted(APP1));
- assertTrue(mBlacklist.isBlacklisted(APP2));
- assertFalse(mBlacklist.isBlacklisted(APP3));
+ assertTrue(mDenylist.isDenylisted(APP1));
+ assertTrue(mDenylist.isDenylisted(APP2));
+ assertFalse(mDenylist.isDenylisted(APP3));
}
@Test
- public void testNoDefaultBlacklist() {
+ public void testNoDefaultDenylist() {
final Resources r = createResources();
- mBlacklist = new HighRefreshRateBlacklist(r, new FakeDeviceConfig());
+ mDenylist = new HighRefreshRateDenylist(r, new FakeDeviceConfig());
- assertFalse(mBlacklist.isBlacklisted(APP1));
+ assertFalse(mDenylist.isDenylisted(APP1));
}
@Test
- public void testDefaultBlacklistIsOverriddenByDeviceConfig() {
+ public void testDefaultDenylistIsOverriddenByDeviceConfig() {
final Resources r = createResources(APP1);
final FakeDeviceConfig config = new FakeDeviceConfig();
- config.setBlacklist(APP2 + "," + APP3);
- mBlacklist = new HighRefreshRateBlacklist(r, config);
+ config.setDenylist(APP2 + "," + APP3);
+ mDenylist = new HighRefreshRateDenylist(r, config);
- assertFalse(mBlacklist.isBlacklisted(APP1));
- assertTrue(mBlacklist.isBlacklisted(APP2));
- assertTrue(mBlacklist.isBlacklisted(APP3));
+ assertFalse(mDenylist.isDenylisted(APP1));
+ assertTrue(mDenylist.isDenylisted(APP2));
+ assertTrue(mDenylist.isDenylisted(APP3));
}
@Test
- public void testDefaultBlacklistIsOverriddenByEmptyDeviceConfig() {
+ public void testDefaultDenylistIsOverriddenByEmptyDeviceConfig() {
final Resources r = createResources(APP1);
final FakeDeviceConfig config = new FakeDeviceConfig();
- config.setBlacklist("");
- mBlacklist = new HighRefreshRateBlacklist(r, config);
+ config.setDenylist("");
+ mDenylist = new HighRefreshRateDenylist(r, config);
- assertFalse(mBlacklist.isBlacklisted(APP1));
+ assertFalse(mDenylist.isDenylisted(APP1));
}
@Test
- public void testDefaultBlacklistIsOverriddenByDeviceConfigUpdate() {
+ public void testDefaultDenylistIsOverriddenByDeviceConfigUpdate() {
final Resources r = createResources(APP1);
final FakeDeviceConfig config = new FakeDeviceConfig();
- mBlacklist = new HighRefreshRateBlacklist(r, config);
+ mDenylist = new HighRefreshRateDenylist(r, config);
// First check that the default denylist is in effect
- assertTrue(mBlacklist.isBlacklisted(APP1));
- assertFalse(mBlacklist.isBlacklisted(APP2));
- assertFalse(mBlacklist.isBlacklisted(APP3));
+ assertTrue(mDenylist.isDenylisted(APP1));
+ assertFalse(mDenylist.isDenylisted(APP2));
+ assertFalse(mDenylist.isDenylisted(APP3));
// Then confirm that the DeviceConfig list has propagated and taken effect.
- config.setBlacklist(APP2 + "," + APP3);
- assertFalse(mBlacklist.isBlacklisted(APP1));
- assertTrue(mBlacklist.isBlacklisted(APP2));
- assertTrue(mBlacklist.isBlacklisted(APP3));
+ config.setDenylist(APP2 + "," + APP3);
+ assertFalse(mDenylist.isDenylisted(APP1));
+ assertTrue(mDenylist.isDenylisted(APP2));
+ assertTrue(mDenylist.isDenylisted(APP3));
// Finally make sure we go back to the default list if the DeviceConfig gets deleted.
- config.setBlacklist(null);
- assertTrue(mBlacklist.isBlacklisted(APP1));
- assertFalse(mBlacklist.isBlacklisted(APP2));
- assertFalse(mBlacklist.isBlacklisted(APP3));
+ config.setDenylist(null);
+ assertTrue(mDenylist.isDenylisted(APP1));
+ assertFalse(mDenylist.isDenylisted(APP2));
+ assertFalse(mDenylist.isDenylisted(APP3));
}
@Test
public void testOverriddenByDeviceConfigUnrelatedFlagChanged() {
final Resources r = createResources(APP1);
final FakeDeviceConfig config = new FakeDeviceConfig();
- mBlacklist = new HighRefreshRateBlacklist(r, config);
- config.setBlacklist(APP2 + "," + APP3);
- assertFalse(mBlacklist.isBlacklisted(APP1));
- assertTrue(mBlacklist.isBlacklisted(APP2));
- assertTrue(mBlacklist.isBlacklisted(APP3));
+ mDenylist = new HighRefreshRateDenylist(r, config);
+ config.setDenylist(APP2 + "," + APP3);
+ assertFalse(mDenylist.isDenylisted(APP1));
+ assertTrue(mDenylist.isDenylisted(APP2));
+ assertTrue(mDenylist.isDenylisted(APP3));
// Change an unrelated flag in our namespace and verify that the denylist is intact
config.putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, "someKey", "someValue");
- assertFalse(mBlacklist.isBlacklisted(APP1));
- assertTrue(mBlacklist.isBlacklisted(APP2));
- assertTrue(mBlacklist.isBlacklisted(APP3));
+ assertFalse(mDenylist.isDenylisted(APP1));
+ assertTrue(mDenylist.isDenylisted(APP2));
+ assertTrue(mDenylist.isDenylisted(APP3));
}
- private Resources createResources(String... defaultBlacklist) {
+ private Resources createResources(String... defaultDenylist) {
Resources r = mock(Resources.class);
when(r.getStringArray(R.array.config_highRefreshRateBlacklist))
- .thenReturn(defaultBlacklist);
+ .thenReturn(defaultDenylist);
return r;
}
@@ -160,9 +160,9 @@ public class HighRefreshRateBlacklistTest {
super.addOnPropertiesChangedListener(namespace, executor, listener);
}
- void setBlacklist(String blacklist) {
+ void setDenylist(String denylist) {
putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
- KEY_HIGH_REFRESH_RATE_BLACKLIST, blacklist);
+ KEY_HIGH_REFRESH_RATE_BLACKLIST, denylist);
}
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index e887be0c48c2..77a4b0507a42 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -48,7 +48,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
private static final int LOW_MODE_ID = 3;
private RefreshRatePolicy mPolicy;
- private HighRefreshRateBlacklist mBlacklist = mock(HighRefreshRateBlacklist.class);
+ private HighRefreshRateDenylist mDenylist = mock(HighRefreshRateDenylist.class);
@Before
public void setUp() {
@@ -61,7 +61,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
defaultMode.getPhysicalWidth(), defaultMode.getPhysicalHeight(), 60),
};
di.defaultModeId = 1;
- mPolicy = new RefreshRatePolicy(mWm, di, mBlacklist);
+ mPolicy = new RefreshRatePolicy(mWm, di, mDenylist);
}
@Test
@@ -81,7 +81,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
final WindowState blacklistedWindow = createWindow(null, TYPE_BASE_APPLICATION,
"blacklistedWindow");
blacklistedWindow.mAttrs.packageName = "com.android.test";
- when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+ when(mDenylist.isDenylisted("com.android.test")).thenReturn(true);
assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(blacklistedWindow));
}
@@ -90,7 +90,7 @@ public class RefreshRatePolicyTest extends WindowTestsBase {
final WindowState overrideWindow = createWindow(null, TYPE_BASE_APPLICATION,
"overrideWindow");
overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
- when(mBlacklist.isBlacklisted("com.android.test")).thenReturn(true);
+ when(mDenylist.isDenylisted("com.android.test")).thenReturn(true);
assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index ef74861e9422..25ba6db38e05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -68,6 +68,7 @@ import com.android.compatibility.common.util.SystemUtil;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
@@ -142,6 +143,9 @@ public class ScreenDecorWindowTests {
assertInsetGreaterOrEqual(mTestActivity, RIGHT, mDecorThickness);
}
+ // Decor windows (i.e windows using PRIVATE_FLAG_IS_SCREEN_DECOR) are no longer supported.
+ // PRIVATE_FLAG_IS_SCREEN_DECOR and related code will be deprecated/removed soon.
+ @Ignore
@Test
public void testMultipleDecors() {
// Test 2 decor windows on-top.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index da3319acca24..4d88a4f7db16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -337,7 +337,7 @@ public class SystemServicesTestRule implements TestRule {
// HighRefreshRateBlacklist with DeviceConfig. We need to undo that here to avoid
// leaking mWmService.
mWmService.mConstants.dispose();
- mWmService.mHighRefreshRateBlacklist.dispose();
+ mWmService.mHighRefreshRateDenylist.dispose();
// This makes sure the posted messages without delay are processed, e.g.
// DisplayPolicy#release, WindowManagerService#setAnimationScale.
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 7c150f9c8db9..0af6266d1642 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -115,13 +115,13 @@ static bool validateFile(const char* filename) {
}
case FILETYPE_INPUTDEVICECONFIGURATION: {
- PropertyMap* map;
- status_t status = PropertyMap::load(String8(filename), &map);
- if (status) {
- error("Error %d parsing input device configuration file.\n\n", status);
+ android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
+ PropertyMap::load(String8(filename));
+ if (!propertyMap.ok()) {
+ error("Error %d parsing input device configuration file.\n\n",
+ propertyMap.error().code());
return false;
}
- delete map;
break;
}
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 3f5c673eeb81..1c297e7058dd 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -798,9 +798,15 @@ package android.net.wifi.hotspot2.pps {
method public int describeContents();
method public String getFqdn();
method public String getFriendlyName();
+ method @Nullable public long[] getMatchAllOis();
+ method @Nullable public long[] getMatchAnyOis();
+ method @Nullable public String[] getOtherHomePartners();
method public long[] getRoamingConsortiumOis();
method public void setFqdn(String);
method public void setFriendlyName(String);
+ method public void setMatchAllOis(@Nullable long[]);
+ method public void setMatchAnyOis(@Nullable long[]);
+ method public void setOtherHomePartners(@Nullable String[]);
method public void setRoamingConsortiumOis(long[]);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.pps.HomeSp> CREATOR;
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index aab4a2df7633..fd45ebec80ef 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -508,7 +508,7 @@ package android.net.wifi {
field public static final int EASY_CONNECT_NETWORK_ROLE_AP = 1; // 0x1
field public static final int EASY_CONNECT_NETWORK_ROLE_STA = 0; // 0x0
field public static final String EXTRA_CHANGE_REASON = "changeReason";
- field public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
+ field @Deprecated public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
field public static final String EXTRA_MULTIPLE_NETWORKS_CHANGED = "multipleChanges";
field public static final String EXTRA_OSU_NETWORK = "android.net.wifi.extra.OSU_NETWORK";
field public static final String EXTRA_PREVIOUS_WIFI_AP_STATE = "previous_wifi_state";
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c76f4a63a777..2219bfcd6aab 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1053,9 +1053,6 @@ public class WifiManager {
/**
* Broadcast intent action indicating that the link configuration changed on wifi.
- * <br />Included Extras:
- * <br />{@link #EXTRA_LINK_PROPERTIES}: {@link android.net.LinkProperties} object associated
- * with the Wi-Fi network.
* <br /> No permissions are required to listen to this broadcast.
* @hide
*/
@@ -1071,8 +1068,12 @@ public class WifiManager {
* Included in the {@link #ACTION_LINK_CONFIGURATION_CHANGED} broadcast.
*
* Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
+ *
+ * @deprecated this extra is no longer populated.
+ *
* @hide
*/
+ @Deprecated
@SystemApi
public static final String EXTRA_LINK_PROPERTIES = "android.net.wifi.extra.LINK_PROPERTIES";
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 8f34579f6a5d..35a8ff6095e0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -16,6 +16,7 @@
package android.net.wifi.hotspot2.pps;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -139,16 +140,26 @@ public final class HomeSp implements Parcelable {
* (MO) tree for more detail.
*/
private long[] mMatchAllOis = null;
+
/**
- * @hide
+ * Set a list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+ * Consortium advertised by a hotspot operator. The list set by this API will have precedence
+ * over {@link #setMatchAnyOis(long[])}, meaning the list set in {@link #setMatchAnyOis(long[])}
+ * will only be used for matching if the list set by this API is null or empty.
+ *
+ * @param matchAllOis An array of longs containing the HomeOIs
*/
- public void setMatchAllOis(long[] matchAllOis) {
+ public void setMatchAllOis(@Nullable long[] matchAllOis) {
mMatchAllOis = matchAllOis;
}
+
/**
- * @hide
+ * Get the list of HomeOIs such that all OIs in the list must match an OI in the Roaming
+ * Consortium advertised by a hotspot operator.
+ *
+ * @return An array of longs containing the HomeOIs
*/
- public long[] getMatchAllOis() {
+ public @Nullable long[] getMatchAllOis() {
return mMatchAllOis;
}
@@ -159,23 +170,34 @@ public final class HomeSp implements Parcelable {
* of that Hotspot provider (e.g. successful authentication with such Hotspot
* is possible).
*
- * {@link #mMatchAllOIs} will have precedence over this one, meaning this list will
- * only be used for matching if {@link #mMatchAllOIs} is null or empty.
+ * The list set by {@link #setMatchAllOis(long[])} will have precedence over this one, meaning
+ * this list will only be used for matching if the list set by {@link #setMatchAllOis(long[])}
+ * is null or empty.
*
* Refer to HomeSP/HomeOIList subtree in PerProviderSubscription (PPS) Management Object
* (MO) tree for more detail.
*/
private long[] mMatchAnyOis = null;
+
/**
- * @hide
+ * Set a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+ * advertised by a hotspot operator. The list set by {@link #setMatchAllOis(long[])}
+ * will have precedence over this API, meaning this list will only be used for matching if the
+ * list set by {@link #setMatchAllOis(long[])} is null or empty.
+ *
+ * @param matchAnyOis An array of longs containing the HomeOIs
*/
- public void setMatchAnyOis(long[] matchAnyOis) {
+ public void setMatchAnyOis(@Nullable long[] matchAnyOis) {
mMatchAnyOis = matchAnyOis;
}
+
/**
- * @hide
+ * Get a list of HomeOIs such that any OI in the list matches an OI in the Roaming Consortium
+ * advertised by a hotspot operator.
+ *
+ * @return An array of longs containing the HomeOIs
*/
- public long[] getMatchAnyOis() {
+ public @Nullable long[] getMatchAnyOis() {
return mMatchAnyOis;
}
@@ -186,16 +208,25 @@ public final class HomeSp implements Parcelable {
* operator merges between the providers.
*/
private String[] mOtherHomePartners = null;
+
/**
- * @hide
+ * Set the list of FQDN (Fully Qualified Domain Name) of other Home partner providers.
+ *
+ * @param otherHomePartners Array of Strings containing the FQDNs of other Home partner
+ * providers
*/
- public void setOtherHomePartners(String[] otherHomePartners) {
+ public void setOtherHomePartners(@Nullable String[] otherHomePartners) {
mOtherHomePartners = otherHomePartners;
}
+
/**
- * @hide
+ * Get the list of FQDN (Fully Qualified Domain Name) of other Home partner providers set in
+ * the profile.
+ *
+ * @return Array of Strings containing the FQDNs of other Home partner providers set in the
+ * profile
*/
- public String[] getOtherHomePartners() {
+ public @Nullable String[] getOtherHomePartners() {
return mOtherHomePartners;
}