summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--OWNERS1
-rw-r--r--apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java122
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java9
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java17
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java68
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java34
-rw-r--r--apex/media/framework/java/android/media/MediaTranscodeManager.java87
-rw-r--r--core/api/current.txt2
-rw-r--r--core/api/module-lib-current.txt3
-rw-r--r--core/api/system-current.txt7
-rw-r--r--core/api/test-current.txt6
-rw-r--r--core/java/android/app/Notification.java141
-rw-r--r--core/java/android/app/SystemServiceRegistry.java9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java1
-rw-r--r--core/java/android/app/admin/DevicePolicySafetyChecker.java15
-rw-r--r--core/java/android/app/role/RoleControllerManager.java26
-rw-r--r--core/java/android/app/role/RoleManager.java42
-rw-r--r--core/java/android/app/time/LocationTimeZoneManager.java76
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java64
-rw-r--r--core/java/android/apphibernation/OWNERS2
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/hardware/biometrics/OWNERS5
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java6
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl2
-rw-r--r--core/java/android/hardware/fingerprint/OWNERS5
-rw-r--r--core/java/android/net/NetworkStatsHistory.java18
-rw-r--r--core/java/android/os/FileUtils.java3
-rw-r--r--core/java/android/service/notification/NotificationListenerFilter.java4
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java16
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java139
-rw-r--r--core/java/android/service/voice/VoiceInteractionService.java3
-rw-r--r--core/java/android/util/TypedValue.java144
-rw-r--r--core/java/android/view/NotificationHeaderView.java15
-rw-r--r--core/java/android/view/WindowManager.java11
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java4
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java276
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java18
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java9
-rw-r--r--core/java/android/view/inputmethod/SurroundingText.java28
-rw-r--r--core/java/android/webkit/TEST_MAPPING36
-rw-r--r--core/java/android/widget/RemoteViews.java260
-rw-r--r--core/java/android/widget/TextView.java35
-rw-r--r--core/java/android/window/ITransitionPlayer.aidl6
-rw-r--r--core/java/android/window/TransitionInfo.java23
-rw-r--r--core/java/com/android/internal/inputmethod/CallbackUtils.java25
-rw-r--r--core/java/com/android/internal/inputmethod/Completable.java54
-rw-r--r--core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl24
-rw-r--r--core/java/com/android/internal/inputmethod/ResultCallbacks.java35
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java2
-rw-r--r--core/java/com/android/internal/os/KernelCpuUidTimeReader.java4
-rw-r--r--core/java/com/android/internal/util/LatencyTracker.java20
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java31
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl2
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java13
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java9
-rw-r--r--core/tests/coretests/src/android/util/TypedValueTest.kt155
-rw-r--r--core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java89
-rw-r--r--core/tests/coretests/src/android/widget/TextViewTest.java28
-rw-r--r--graphics/java/android/graphics/RecordingCanvas.java23
-rw-r--r--graphics/java/android/graphics/RuntimeShader.java4
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_controls.xml33
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml48
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml (renamed from libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml)2
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu_additional_action_button.xml (renamed from libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml)2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java201
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java342
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java97
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java61
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java158
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java126
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java (renamed from libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java)88
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java157
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java235
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt28
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt145
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml1
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java2
-rw-r--r--libs/hwui/SkiaCanvas.cpp12
-rw-r--r--libs/hwui/SkiaCanvas.h6
-rw-r--r--libs/hwui/canvas/CanvasOpTypes.h1
-rw-r--r--libs/hwui/canvas/CanvasOps.h37
-rw-r--r--libs/hwui/hwui/Canvas.h7
-rw-r--r--libs/hwui/hwui/ImageDecoder.cpp267
-rw-r--r--libs/hwui/hwui/ImageDecoder.h52
-rw-r--r--libs/hwui/jni/android_graphics_DisplayListCanvas.cpp18
-rw-r--r--libs/hwui/pipeline/skia/AnimatedDrawables.h54
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp10
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.h6
-rw-r--r--media/java/android/media/ExifInterface.java17
-rw-r--r--media/java/android/media/musicrecognition/OWNERS6
-rw-r--r--media/java/android/media/session/MediaSessionManager.java3
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendInfo.java4
-rw-r--r--native/graphics/jni/imagedecoder.cpp176
-rw-r--r--native/graphics/jni/libjnigraphics.map.txt11
-rw-r--r--native/webview/TEST_MAPPING36
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java12
-rw-r--r--packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java35
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java47
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java21
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res-keyguard/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-bg/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ca/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-eu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-hy/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-is/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-it/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-mn/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-pl/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-si/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-sr/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-te/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-uk/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-uz/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml2
-rw-r--r--packages/SystemUI/res/values-af/strings.xml8
-rw-r--r--packages/SystemUI/res/values-am/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml8
-rw-r--r--packages/SystemUI/res/values-as/strings.xml8
-rw-r--r--packages/SystemUI/res/values-az/strings.xml8
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml8
-rw-r--r--packages/SystemUI/res/values-be/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml8
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml8
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml8
-rw-r--r--packages/SystemUI/res/values-cs/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-da/strings.xml8
-rw-r--r--packages/SystemUI/res/values-de/strings.xml8
-rw-r--r--packages/SystemUI/res/values-el/strings.xml8
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es/strings.xml9
-rw-r--r--packages/SystemUI/res/values-et/strings.xml8
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml8
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml8
-rw-r--r--packages/SystemUI/res/values-hu/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml6
-rw-r--r--packages/SystemUI/res/values-in/strings.xml8
-rw-r--r--packages/SystemUI/res/values-is/strings.xml8
-rw-r--r--packages/SystemUI/res/values-it/strings.xml8
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml20
-rw-r--r--packages/SystemUI/res/values-iw/strings_tv.xml4
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml8
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-km/strings.xml8
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml8
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml8
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml8
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml8
-rw-r--r--packages/SystemUI/res/values-my/strings.xml8
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-or/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml10
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml8
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ru/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sl/strings_tv.xml4
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml14
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml8
-rw-r--r--packages/SystemUI/res/values-sv/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml8
-rw-r--r--packages/SystemUI/res/values-te/strings.xml8
-rw-r--r--packages/SystemUI/res/values-th/strings.xml12
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml8
-rw-r--r--packages/SystemUI/res/values-tr/strings_tv.xml2
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml8
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml8
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml8
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml8
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java163
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java117
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java2
-rw-r--r--services/core/java/com/android/server/IntentResolver.java12
-rw-r--r--services/core/java/com/android/server/WatchableIntentResolver.java (renamed from services/core/java/com/android/server/utils/WatchableIntentResolver.java)23
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java2
-rw-r--r--services/core/java/com/android/server/apphibernation/OWNERS3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java21
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RemovalClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java3
-rw-r--r--services/core/java/com/android/server/content/OWNERS1
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java28
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java6
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java92
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java15
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java11
-rw-r--r--services/core/java/com/android/server/display/HighBrightnessModeController.java260
-rw-r--r--services/core/java/com/android/server/location/timezone/ControllerImpl.java32
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java109
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerServiceState.java97
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerShellCommand.java188
-rw-r--r--services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java44
-rw-r--r--services/core/java/com/android/server/media/MediaShellCommand.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkIdentitySet.java12
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java19
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsRecorder.java5
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/AppsFilter.java17
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileIntentResolver.java4
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java3
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java4
-rw-r--r--services/core/java/com/android/server/pm/PreferredIntentResolver.java4
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java14
-rw-r--r--services/core/java/com/android/server/pm/Settings.java113
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java14
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java81
-rw-r--r--services/core/java/com/android/server/utils/Watchable.java49
-rw-r--r--services/core/java/com/android/server/utils/WatchableImpl.java14
-rw-r--r--services/core/java/com/android/server/utils/Watched.java32
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayList.java416
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayMap.java52
-rw-r--r--services/core/java/com/android/server/utils/WatchedArraySet.java434
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseArray.java63
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java76
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseIntArray.java323
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java1
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java13
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java1
-rw-r--r--services/core/java/com/android/server/wm/Task.java19
-rw-r--r--services/core/java/com/android/server/wm/Transition.java12
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java32
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd33
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt24
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java16
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java27
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java58
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java9
-rw-r--r--services/musicrecognition/OWNERS6
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java44
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java41
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java41
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java37
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java69
-rw-r--r--services/tests/servicestests/src/com/android/server/location/timezone/LocationTimeZoneProviderTest.java50
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java75
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/utils/WatcherTest.java349
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TransitionTests.java12
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt15
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt3
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt3
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java24
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java7
436 files changed, 8709 insertions, 1997 deletions
diff --git a/OWNERS b/OWNERS
index 4160122532ff..710f13e4f568 100644
--- a/OWNERS
+++ b/OWNERS
@@ -9,6 +9,7 @@ hackbod@google.com
jjaggi@google.com
jsharkey@android.com
jsharkey@google.com
+lorenzo@google.com
michaelwr@google.com
nandana@google.com
narayan@google.com
diff --git a/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java b/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.java
new file mode 100644
index 000000000000..fcbfc7212351
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/mtp_perf/AppFusePerfTest.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 android.mtp_perf;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class AppFusePerfTest {
+ static final int SIZE = 10 * 1024 * 1024; // 10MB
+
+ @Test
+ public void testReadWriteFile() throws IOException {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final StorageManager storageManager = context.getSystemService(StorageManager.class);
+
+ final byte[] bytes = new byte[SIZE];
+ final int samples = 100;
+ final double[] readTime = new double[samples];
+ final double[] writeTime = new double[samples];
+
+ for (int i = 0; i < samples; i++) {
+ final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+ ParcelFileDescriptor.MODE_READ_ONLY, new TestCallback());
+ try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+ final long startTime = System.nanoTime();
+ stream.read(bytes);
+ readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+ }
+ }
+
+ for (int i = 0; i < samples; i++) {
+ final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+ ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE,
+ new TestCallback());
+ try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ final long startTime = System.nanoTime();
+ stream.write(bytes);
+ writeTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+ }
+ }
+
+ double readAverage = 0;
+ double writeAverage = 0;
+ double readSquaredAverage = 0;
+ double writeSquaredAverage = 0;
+ for (int i = 0; i < samples; i++) {
+ readAverage += readTime[i];
+ writeAverage += writeTime[i];
+ readSquaredAverage += readTime[i] * readTime[i];
+ writeSquaredAverage += writeTime[i] * writeTime[i];
+ }
+
+ readAverage /= samples;
+ writeAverage /= samples;
+ readSquaredAverage /= samples;
+ writeSquaredAverage /= samples;
+
+ final Bundle results = new Bundle();
+ results.putDouble("readAverage", readAverage);
+ results.putDouble("readStandardDeviation",
+ Math.sqrt(readSquaredAverage - readAverage * readAverage));
+ results.putDouble("writeAverage", writeAverage);
+ results.putDouble("writeStandardDeviation",
+ Math.sqrt(writeSquaredAverage - writeAverage * writeAverage));
+ InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
+ }
+
+ private static class TestCallback extends ProxyFileDescriptorCallback {
+ @Override
+ public long onGetSize() throws ErrnoException {
+ return SIZE;
+ }
+
+ @Override
+ public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+ return size;
+ }
+
+ @Override
+ public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+ return size;
+ }
+
+ @Override
+ public void onFsync() throws ErrnoException {}
+
+ @Override
+ public void onRelease() {}
+ }
+}
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 df0a0ee38674..35dadf06f4b8 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1978,9 +1978,12 @@ public class JobSchedulerService extends com.android.server.SystemService
JobStatus runNow = (JobStatus) message.obj;
// runNow can be null, which is a controller's way of indicating that its
// state is such that all ready jobs should be run immediately.
- if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
- mJobPackageTracker.notePending(runNow);
- addOrderedItem(mPendingJobs, runNow, sPendingJobComparator);
+ if (runNow != null) {
+ if (!isCurrentlyActiveLocked(runNow)
+ && isReadyToBeExecutedLocked(runNow)) {
+ mJobPackageTracker.notePending(runNow);
+ addOrderedItem(mPendingJobs, runNow, sPendingJobComparator);
+ }
} else {
queueReadyJobsForExecutionLocked();
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 6ddafadaa871..d5130dc97bbc 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -217,20 +217,6 @@ public final class ConnectivityController extends RestrictingController implemen
return jobs != null && jobs.size() > 0;
}
- @VisibleForTesting
- @GuardedBy("mLock")
- boolean wouldBeReadyWithConnectivityLocked(JobStatus jobStatus) {
- final boolean networkAvailable = isNetworkAvailable(jobStatus);
- if (DEBUG) {
- Slog.v(TAG, "wouldBeReadyWithConnectivityLocked: " + jobStatus.toShortString()
- + " networkAvailable=" + networkAvailable);
- }
- // If the network isn't available, then requesting an exception won't help.
-
- return networkAvailable && wouldBeReadyWithConstraintLocked(jobStatus,
- JobStatus.CONSTRAINT_CONNECTIVITY);
- }
-
/**
* Tell NetworkPolicyManager not to block a UID's network connection if that's the only
* thing stopping a job from running.
@@ -243,7 +229,8 @@ public final class ConnectivityController extends RestrictingController implemen
}
// Always check the full job readiness stat in case the component has been disabled.
- if (wouldBeReadyWithConnectivityLocked(jobStatus)) {
+ if (wouldBeReadyWithConstraintLocked(jobStatus, JobStatus.CONSTRAINT_CONNECTIVITY)
+ && isNetworkAvailable(jobStatus)) {
if (DEBUG) {
Slog.i(TAG, "evaluateStateLocked finds job " + jobStatus + " would be ready.");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 2d55aa5d5495..a02f8de5e292 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -43,6 +43,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManagerInternal;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.Handler;
@@ -64,6 +65,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.job.ConstantsProto;
@@ -507,6 +509,8 @@ public final class QuotaController extends StateController {
QcConstants.DEFAULT_EJ_LIMIT_RESTRICTED_MS
};
+ private long mEjLimitSpecialAdditionMs = QcConstants.DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS;
+
/**
* The period of time used to calculate expedited job sessions. Apps can only have expedited job
* sessions totalling {@link #mEJLimitsMs}[bucket within this period of time (without factoring
@@ -517,22 +521,26 @@ public final class QuotaController extends StateController {
/**
* Length of time used to split an app's top time into chunks.
*/
- public long mEJTopAppTimeChunkSizeMs = QcConstants.DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
+ private long mEJTopAppTimeChunkSizeMs = QcConstants.DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS;
/**
* How much EJ quota to give back to an app based on the number of top app time chunks it had.
*/
- public long mEJRewardTopAppMs = QcConstants.DEFAULT_EJ_REWARD_TOP_APP_MS;
+ private long mEJRewardTopAppMs = QcConstants.DEFAULT_EJ_REWARD_TOP_APP_MS;
/**
* How much EJ quota to give back to an app based on each non-top user interaction.
*/
- public long mEJRewardInteractionMs = QcConstants.DEFAULT_EJ_REWARD_INTERACTION_MS;
+ private long mEJRewardInteractionMs = QcConstants.DEFAULT_EJ_REWARD_INTERACTION_MS;
/**
* How much EJ quota to give back to an app based on each notification seen event.
*/
- public long mEJRewardNotificationSeenMs = QcConstants.DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
+ private long mEJRewardNotificationSeenMs = QcConstants.DEFAULT_EJ_REWARD_NOTIFICATION_SEEN_MS;
+
+ /** The package verifier app. */
+ @Nullable
+ private String mPackageVerifier;
/** An app has reached its quota. The message should contain a {@link Package} object. */
@VisibleForTesting
@@ -588,6 +596,16 @@ public final class QuotaController extends StateController {
}
@Override
+ public void onSystemServicesReady() {
+ String[] pkgNames = LocalServices.getService(PackageManagerInternal.class)
+ .getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM);
+ synchronized (mLock) {
+ mPackageVerifier = ArrayUtils.firstOrNull(pkgNames);
+ }
+ }
+
+ @Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
@@ -875,7 +893,7 @@ public final class QuotaController extends StateController {
if (quota.getStandbyBucketLocked() == NEVER_INDEX) {
return 0;
}
- final long limitMs = mEJLimitsMs[quota.getStandbyBucketLocked()];
+ final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
long remainingMs = limitMs - quota.getTallyLocked();
// Stale sessions may still be factored into tally. Make sure they're removed.
@@ -912,6 +930,14 @@ public final class QuotaController extends StateController {
return remainingMs - timer.getCurrentDuration(sElapsedRealtimeClock.millis());
}
+ private long getEJLimitMsLocked(@NonNull final String packageName, final int standbyBucket) {
+ final long baseLimitMs = mEJLimitsMs[standbyBucket];
+ if (packageName.equals(mPackageVerifier)) {
+ return baseLimitMs + mEjLimitSpecialAdditionMs;
+ }
+ return baseLimitMs;
+ }
+
/**
* Returns the amount of time, in milliseconds, until the package would have reached its
* duration quota, assuming it has a job counting towards its quota the entire time. This takes
@@ -1014,7 +1040,7 @@ public final class QuotaController extends StateController {
final long nowElapsed = sElapsedRealtimeClock.millis();
ShrinkableDebits quota = getEJQuotaLocked(userId, packageName);
- final long limitMs = mEJLimitsMs[quota.getStandbyBucketLocked()];
+ final long limitMs = getEJLimitMsLocked(packageName, quota.getStandbyBucketLocked());
final long startWindowElapsed = Math.max(0, nowElapsed - mEJLimitWindowSizeMs);
long remainingDeadSpaceMs = remainingExecutionTimeMs;
// Total time looked at where a session wouldn't be phasing out.
@@ -1606,7 +1632,7 @@ public final class QuotaController extends StateController {
inRegularQuotaTimeElapsed = inQuotaTimeElapsed;
}
if (remainingEJQuota <= 0) {
- final long limitMs = mEJLimitsMs[standbyBucket] - mQuotaBufferMs;
+ final long limitMs = getEJLimitMsLocked(packageName, standbyBucket) - mQuotaBufferMs;
long sumMs = 0;
final Timer ejTimer = mEJPkgTimers.get(userId, packageName);
if (ejTimer != null && ejTimer.isActive()) {
@@ -2741,6 +2767,9 @@ public final class QuotaController extends StateController {
static final String KEY_EJ_LIMIT_RESTRICTED_MS =
QC_CONSTANT_PREFIX + "ej_limit_restricted_ms";
@VisibleForTesting
+ static final String KEY_EJ_LIMIT_SPECIAL_ADDITION_MS =
+ QC_CONSTANT_PREFIX + "ej_limit_special_addition_ms";
+ @VisibleForTesting
static final String KEY_EJ_WINDOW_SIZE_MS =
QC_CONSTANT_PREFIX + "ej_window_size_ms";
@VisibleForTesting
@@ -2801,6 +2830,7 @@ public final class QuotaController extends StateController {
private static final long DEFAULT_EJ_LIMIT_FREQUENT_MS = 10 * MINUTE_IN_MILLIS;
private static final long DEFAULT_EJ_LIMIT_RARE_MS = DEFAULT_EJ_LIMIT_FREQUENT_MS;
private static final long DEFAULT_EJ_LIMIT_RESTRICTED_MS = 5 * MINUTE_IN_MILLIS;
+ private static final long DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS = 30 * MINUTE_IN_MILLIS;
private static final long DEFAULT_EJ_WINDOW_SIZE_MS = 24 * HOUR_IN_MILLIS;
private static final long DEFAULT_EJ_TOP_APP_TIME_CHUNK_SIZE_MS = 30 * SECOND_IN_MILLIS;
private static final long DEFAULT_EJ_REWARD_TOP_APP_MS = 10 * SECOND_IN_MILLIS;
@@ -3001,6 +3031,11 @@ public final class QuotaController extends StateController {
public long EJ_LIMIT_RESTRICTED_MS = DEFAULT_EJ_LIMIT_RESTRICTED_MS;
/**
+ * How much additional EJ quota special, critical apps should get.
+ */
+ public long EJ_LIMIT_SPECIAL_ADDITION_MS = DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS;
+
+ /**
* The period of time used to calculate expedited job sessions. Apps can only have expedited
* job sessions totalling EJ_LIMIT_<bucket>_MS within this period of time (without factoring
* in any rewards or free EJs).
@@ -3053,6 +3088,7 @@ public final class QuotaController extends StateController {
case KEY_EJ_LIMIT_FREQUENT_MS:
case KEY_EJ_LIMIT_RARE_MS:
case KEY_EJ_LIMIT_RESTRICTED_MS:
+ case KEY_EJ_LIMIT_SPECIAL_ADDITION_MS:
case KEY_EJ_WINDOW_SIZE_MS:
updateEJLimitConstantsLocked();
break;
@@ -3376,7 +3412,8 @@ public final class QuotaController extends StateController {
DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_EJ_LIMIT_ACTIVE_MS, KEY_EJ_LIMIT_WORKING_MS,
KEY_EJ_LIMIT_FREQUENT_MS, KEY_EJ_LIMIT_RARE_MS,
- KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_WINDOW_SIZE_MS);
+ KEY_EJ_LIMIT_RESTRICTED_MS, KEY_EJ_LIMIT_SPECIAL_ADDITION_MS,
+ KEY_EJ_WINDOW_SIZE_MS);
EJ_LIMIT_ACTIVE_MS = properties.getLong(
KEY_EJ_LIMIT_ACTIVE_MS, DEFAULT_EJ_LIMIT_ACTIVE_MS);
EJ_LIMIT_WORKING_MS = properties.getLong(
@@ -3387,6 +3424,8 @@ public final class QuotaController extends StateController {
KEY_EJ_LIMIT_RARE_MS, DEFAULT_EJ_LIMIT_RARE_MS);
EJ_LIMIT_RESTRICTED_MS = properties.getLong(
KEY_EJ_LIMIT_RESTRICTED_MS, DEFAULT_EJ_LIMIT_RESTRICTED_MS);
+ EJ_LIMIT_SPECIAL_ADDITION_MS = properties.getLong(
+ KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, DEFAULT_EJ_LIMIT_SPECIAL_ADDITION_MS);
EJ_WINDOW_SIZE_MS = properties.getLong(
KEY_EJ_WINDOW_SIZE_MS, DEFAULT_EJ_WINDOW_SIZE_MS);
@@ -3432,6 +3471,13 @@ public final class QuotaController extends StateController {
mEJLimitsMs[RESTRICTED_INDEX] = newRestrictedLimitMs;
mShouldReevaluateConstraints = true;
}
+ // The addition must be in the range [0 minutes, window size - active limit].
+ long newSpecialAdditionMs = Math.max(0,
+ Math.min(newWindowSizeMs - newActiveLimitMs, EJ_LIMIT_SPECIAL_ADDITION_MS));
+ if (mEjLimitSpecialAdditionMs != newSpecialAdditionMs) {
+ mEjLimitSpecialAdditionMs = newSpecialAdditionMs;
+ mShouldReevaluateConstraints = true;
+ }
}
private void dump(IndentingPrintWriter pw) {
@@ -3470,6 +3516,7 @@ public final class QuotaController extends StateController {
pw.print(KEY_EJ_LIMIT_FREQUENT_MS, EJ_LIMIT_FREQUENT_MS).println();
pw.print(KEY_EJ_LIMIT_RARE_MS, EJ_LIMIT_RARE_MS).println();
pw.print(KEY_EJ_LIMIT_RESTRICTED_MS, EJ_LIMIT_RESTRICTED_MS).println();
+ pw.print(KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, EJ_LIMIT_SPECIAL_ADDITION_MS).println();
pw.print(KEY_EJ_WINDOW_SIZE_MS, EJ_WINDOW_SIZE_MS).println();
pw.print(KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, EJ_TOP_APP_TIME_CHUNK_SIZE_MS).println();
pw.print(KEY_EJ_REWARD_TOP_APP_MS, EJ_REWARD_TOP_APP_MS).println();
@@ -3593,6 +3640,11 @@ public final class QuotaController extends StateController {
}
@VisibleForTesting
+ long getEjLimitSpecialAdditionMs() {
+ return mEjLimitSpecialAdditionMs;
+ }
+
+ @VisibleForTesting
@NonNull
long getEJLimitWindowSizeMs() {
return mEJLimitWindowSizeMs;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index 2b5aab83463b..ede14ec06c71 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -157,31 +157,27 @@ public final class TimeController extends StateController {
&& !job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE)
&& job.getLatestRunTimeElapsed() <= mNextJobExpiredElapsedMillis) {
if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
- checkExpiredDeadlinesAndResetAlarm();
- checkExpiredDelaysAndResetAlarm();
- } else {
- final boolean isAlarmForJob =
- job.getLatestRunTimeElapsed() == mNextJobExpiredElapsedMillis;
- final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
- job, JobStatus.CONSTRAINT_DEADLINE);
- if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
- checkExpiredDeadlinesAndResetAlarm();
+ if (job.isReady()) {
+ // If the job still isn't ready, there's no point trying to rush the
+ // Scheduler.
+ mStateChangedListener.onRunJobNow(job);
}
+ } else if (wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_DEADLINE)) {
+ // This job's deadline is earlier than the current set alarm. Update the alarm.
+ setDeadlineExpiredAlarmLocked(job.getLatestRunTimeElapsed(),
+ deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
}
}
if (job.hasTimingDelayConstraint()
&& !job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)
&& job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
- if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
- checkExpiredDelaysAndResetAlarm();
- } else {
- final boolean isAlarmForJob =
- job.getEarliestRunTime() == mNextDelayExpiredElapsedMillis;
- final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
- job, JobStatus.CONSTRAINT_TIMING_DELAY);
- if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
- checkExpiredDelaysAndResetAlarm();
- }
+ // Since this is just the delay, we don't need to rush the Scheduler to run the job
+ // immediately if the constraint is satisfied here.
+ if (!evaluateTimingDelayConstraint(job, nowElapsedMillis)
+ && wouldBeReadyWithConstraintLocked(job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
+ // This job's delay is earlier than the current set alarm. Update the alarm.
+ setDelayExpiredAlarmLocked(job.getEarliestRunTime(),
+ deriveWorkSource(job.getSourceUid(), job.getSourcePackageName()));
}
}
}
diff --git a/apex/media/framework/java/android/media/MediaTranscodeManager.java b/apex/media/framework/java/android/media/MediaTranscodeManager.java
index d449289f156f..3d706e40bc0b 100644
--- a/apex/media/framework/java/android/media/MediaTranscodeManager.java
+++ b/apex/media/framework/java/android/media/MediaTranscodeManager.java
@@ -109,6 +109,9 @@ public final class MediaTranscodeManager {
/** Interval between trying to reconnect to the service. */
private static final int INTERVAL_CONNECT_SERVICE_RETRY_MS = 40;
+ /** Default bpp(bits-per-pixel) to use for calculating default bitrate. */
+ private static final float BPP = 0.25f;
+
/**
* Default transcoding type.
* @hide
@@ -1002,15 +1005,93 @@ public final class MediaTranscodeManager {
if (!shouldTranscode()) {
return null;
}
- // TODO(hkuang): Only modified the video codec type, and use fixed bitrate for now.
- // May switch to transcoding profile when it's available.
+
MediaFormat videoTrackFormat = new MediaFormat(mSrcVideoFormatHint);
videoTrackFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
- videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+
+ int width = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_WIDTH);
+ int height = mSrcVideoFormatHint.getInteger(MediaFormat.KEY_HEIGHT);
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException(
+ "Source Width and height must be larger than 0");
+ }
+
+ // TODO(hkuang): Remove the hardcoded frameRate after b/176940364 is fixed.
+ float frameRate = (float) 30.0;
+ /*mSrcVideoFormatHint.getFloat(MediaFormat.KEY_FRAME_RATE, frameRate);
+ if (frameRate <= 0) {
+ throw new IllegalArgumentException(
+ "frameRate must be larger than 0");
+ }*/
+
+ int bitrate = getAVCBitrate(width, height, frameRate);
+ videoTrackFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
return videoTrackFormat;
}
/**
+ * Generate a default bitrate with the fixed bpp(bits-per-pixel) 0.25.
+ * This maps to:
+ * 1080P@30fps -> 16Mbps
+ * 1080P@60fps-> 32Mbps
+ * 4K@30fps -> 62Mbps
+ */
+ private static int getDefaultBitrate(int width, int height, float frameRate) {
+ return (int) (width * height * frameRate * BPP);
+ }
+
+ /**
+ * Query the bitrate from CamcorderProfile. If there are two profiles that match the
+ * width/height/framerate, we will use the higher one to get better quality.
+ * Return default bitrate if could not find any match profile.
+ */
+ private static int getAVCBitrate(int width, int height, float frameRate) {
+ int bitrate = -1;
+ int[] cameraIds = {0, 1};
+
+ // Profiles ordered in decreasing order of preference.
+ int[] preferQualities = {
+ CamcorderProfile.QUALITY_2160P,
+ CamcorderProfile.QUALITY_1080P,
+ CamcorderProfile.QUALITY_720P,
+ CamcorderProfile.QUALITY_480P,
+ CamcorderProfile.QUALITY_LOW,
+ };
+
+ for (int cameraId : cameraIds) {
+ for (int quality : preferQualities) {
+ // Check if camera id has profile for the quality level.
+ if (!CamcorderProfile.hasProfile(cameraId, quality)) {
+ continue;
+ }
+ CamcorderProfile profile = CamcorderProfile.get(cameraId, quality);
+ // Check the width/height/framerate/codec, also consider portrait case.
+ if (((width == profile.videoFrameWidth
+ && height == profile.videoFrameHeight)
+ || (height == profile.videoFrameWidth
+ && width == profile.videoFrameHeight))
+ && (int) frameRate == profile.videoFrameRate
+ && profile.videoCodec == MediaRecorder.VideoEncoder.H264) {
+ if (bitrate < profile.videoBitRate) {
+ bitrate = profile.videoBitRate;
+ }
+ break;
+ }
+ }
+ }
+
+ if (bitrate == -1) {
+ Log.w(TAG, "Failed to find CamcorderProfile for w: " + width + "h: " + height
+ + " fps: "
+ + frameRate);
+ bitrate = getDefaultBitrate(width, height, frameRate);
+ }
+ Log.d(TAG, "Using bitrate " + bitrate + " for " + width + " " + height + " "
+ + frameRate);
+ return bitrate;
+ }
+
+ /**
* Retrieves the audio track format to be used for transcoding.
*
* @return the audio track format to be used if transcoding should be performed, and
diff --git a/core/api/current.txt b/core/api/current.txt
index 29d4915a4953..4ad5e49bf6c0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -50464,6 +50464,7 @@ package android.view.inputmethod {
method public int describeContents();
method public void dump(android.util.Printer, String);
method @Nullable public CharSequence getInitialSelectedText(int);
+ method @Nullable public android.view.inputmethod.SurroundingText getInitialSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int);
method @Nullable public CharSequence getInitialTextAfterCursor(int, int);
method @Nullable public CharSequence getInitialTextBeforeCursor(int, int);
method public final void makeCompatible(int);
@@ -50627,6 +50628,7 @@ package android.view.inputmethod {
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public boolean setComposingText(CharSequence, int);
+ method public default boolean setImeTemporarilyConsumesInput(boolean);
method public boolean setSelection(int, int);
field public static final int CURSOR_UPDATE_IMMEDIATE = 1; // 0x1
field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index f22b0f4b22ad..ef6c8b713c2c 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -109,8 +109,11 @@ 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 dispatchMediaKeyEvent(@NonNull android.view.KeyEvent);
+ method public void dispatchMediaKeyEvent(@NonNull android.view.KeyEvent, boolean);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
+ method public void dispatchVolumeKeyEvent(@NonNull android.view.KeyEvent, int, boolean);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
method @NonNull public java.util.List<android.media.session.MediaController> getActiveSessionsForUser(@Nullable android.content.ComponentName, int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1553214bc2eb..36b565b94db3 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -661,6 +661,10 @@ package android.app {
field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
}
+ public static class Notification.Action implements android.os.Parcelable {
+ field public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11; // 0xb
+ }
+
public static final class Notification.TvExtender implements android.app.Notification.Extender {
ctor public Notification.TvExtender();
ctor public Notification.TvExtender(android.app.Notification);
@@ -1366,6 +1370,8 @@ package android.app.role {
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
@@ -9852,6 +9858,7 @@ package android.service.voice {
field public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 8; // 0x8
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
field public static final int RECOGNITION_MODE_VOICE_TRIGGER = 1; // 0x1
+ field public static final int STATE_ERROR = 3; // 0x3
field public static final int STATE_HARDWARE_UNAVAILABLE = -2; // 0xfffffffe
field public static final int STATE_KEYPHRASE_ENROLLED = 2; // 0x2
field public static final int STATE_KEYPHRASE_UNENROLLED = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1086577b0a39..d226d6252803 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -368,6 +368,7 @@ package android.app {
package android.app.admin {
public class DevicePolicyManager {
+ method public void forceUpdateUserSetupComplete();
method public long getLastBugReportRequestTime();
method public long getLastNetworkLogRetrievalTime();
method public long getLastSecurityLogRetrievalTime();
@@ -441,11 +442,6 @@ package android.app.prediction {
package android.app.role {
- public class RoleControllerManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isApplicationVisibleForRole(@NonNull String, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void isRoleVisible(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- }
-
public final class RoleManager {
method @Nullable public String getSmsRoleHolder(int);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8242e4db16c3..297b9ff1af16 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -30,7 +30,6 @@ import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.Px;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -83,6 +82,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
@@ -218,6 +218,11 @@ public class Notification implements Parcelable
private static final int MAX_REPLY_HISTORY = 5;
/**
+ * Maximum aspect ratio of the large icon. 16:9
+ */
+ private static final float MAX_LARGE_ICON_ASPECT_RATIO = 16f / 9f;
+
+ /**
* Maximum number of (generic) action buttons in a notification (contextual action buttons are
* handled separately).
* @hide
@@ -1523,6 +1528,14 @@ public class Notification implements Parcelable
*/
public static final int SEMANTIC_ACTION_CALL = 10;
+ /**
+ * {@code SemanticAction}: Mark the conversation associated with the notification as a
+ * priority. Note that this is only for use by the notification assistant services.
+ * @hide
+ */
+ @SystemApi
+ public static final int SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY = 11;
+
private final Bundle mExtras;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private Icon mIcon;
@@ -2233,7 +2246,8 @@ public class Notification implements Parcelable
SEMANTIC_ACTION_UNMUTE,
SEMANTIC_ACTION_THUMBS_UP,
SEMANTIC_ACTION_THUMBS_DOWN,
- SEMANTIC_ACTION_CALL
+ SEMANTIC_ACTION_CALL,
+ SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY
})
@Retention(RetentionPolicy.SOURCE)
public @interface SemanticAction {}
@@ -4228,9 +4242,9 @@ public class Notification implements Parcelable
/**
* Add a large icon to the notification content view.
*
- * In the platform template, this image will be shown on the left of the notification view
- * in place of the {@link #setSmallIcon(Icon) small icon} (which will be placed in a small
- * badge atop the large icon).
+ * In the platform template, this image will be shown either on the right of the
+ * notification, with an aspect ratio of up to 16:9, or (when the notification is grouped)
+ * on the left in place of the {@link #setSmallIcon(Icon) small icon}.
*/
@NonNull
public Builder setLargeIcon(Bitmap b) {
@@ -4240,9 +4254,9 @@ public class Notification implements Parcelable
/**
* Add a large icon to the notification content view.
*
- * In the platform template, this image will be shown on the left of the notification view
- * in place of the {@link #setSmallIcon(Icon) small icon} (which will be placed in a small
- * badge atop the large icon).
+ * In the platform template, this image will be shown either on the right of the
+ * notification, with an aspect ratio of up to 16:9, or (when the notification is grouped)
+ * on the left in place of the {@link #setSmallIcon(Icon) small icon}.
*/
@NonNull
public Builder setLargeIcon(Icon icon) {
@@ -4911,7 +4925,8 @@ public class Notification implements Parcelable
setTextViewColorPrimary(contentView, R.id.title, p);
contentView.setViewLayoutWidth(R.id.title, showProgress
? ViewGroup.LayoutParams.WRAP_CONTENT
- : ViewGroup.LayoutParams.MATCH_PARENT);
+ : ViewGroup.LayoutParams.MATCH_PARENT,
+ TypedValue.COMPLEX_UNIT_PX);
}
if (p.text != null && p.text.length() != 0) {
int textId = showProgress ? com.android.internal.R.id.text_line_1
@@ -5109,8 +5124,7 @@ public class Notification implements Parcelable
if (result == null) {
result = new TemplateBindResult();
}
- final boolean largeIconShown = bindLargeIcon(contentView, p);
- calculateLargeIconMarginEnd(largeIconShown, result);
+ bindLargeIcon(contentView, p, result);
if (p.mHeaderless) {
// views in the headerless (collapsed) state
result.mHeadingExtraMarginSet.applyToView(contentView,
@@ -5122,28 +5136,54 @@ public class Notification implements Parcelable
}
}
- private void calculateLargeIconMarginEnd(boolean largeIconShown,
+ // This code is executed on behalf of other apps' notifications, sometimes even by 3p apps,
+ // a use case that is not supported by the Compat Framework library. Workarounds to resolve
+ // the change's state in NotificationManagerService were very complex. These behavior
+ // changes are entirely visual, and should otherwise be undetectable by apps.
+ @SuppressWarnings("AndroidFrameworkCompatChange")
+ private void calculateLargeIconDimens(boolean largeIconShown,
@NonNull TemplateBindResult result) {
final Resources resources = mContext.getResources();
- final int contentMargin = resources.getDimensionPixelOffset(
- R.dimen.notification_content_margin_end);
- final int expanderSize = resources.getDimensionPixelSize(
- R.dimen.notification_header_expand_icon_size) - contentMargin;
- final int extraMarginEndIfVisible = resources.getDimensionPixelSize(
- R.dimen.notification_right_icon_size) + contentMargin;
- result.setRightIconState(largeIconShown, extraMarginEndIfVisible, expanderSize);
+ final float density = resources.getDisplayMetrics().density;
+ final float contentMarginDp = resources.getDimension(
+ R.dimen.notification_content_margin_end) / density;
+ final float expanderSizeDp = resources.getDimension(
+ R.dimen.notification_header_expand_icon_size) / density - contentMarginDp;
+ final float viewHeightDp = resources.getDimension(
+ R.dimen.notification_right_icon_size) / density;
+ float viewWidthDp = viewHeightDp; // icons are 1:1 by default
+ if (largeIconShown && (
+ mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.S
+ || DevFlags.shouldBackportSNotifRules(mContext.getContentResolver()))) {
+ Drawable drawable = mN.mLargeIcon.loadDrawable(mContext);
+ if (drawable != null) {
+ int iconWidth = drawable.getIntrinsicWidth();
+ int iconHeight = drawable.getIntrinsicHeight();
+ if (iconWidth > iconHeight && iconHeight > 0) {
+ final float maxViewWidthDp = viewHeightDp * MAX_LARGE_ICON_ASPECT_RATIO;
+ viewWidthDp = Math.min(viewHeightDp * iconWidth / iconHeight,
+ maxViewWidthDp);
+ }
+ }
+ }
+ final float extraMarginEndDpIfVisible = viewWidthDp + contentMarginDp;
+ result.setRightIconState(largeIconShown, viewWidthDp,
+ extraMarginEndDpIfVisible, expanderSizeDp);
}
/**
* Bind the large icon.
- * @return if the largeIcon is visible
*/
- private boolean bindLargeIcon(RemoteViews contentView, StandardTemplateParams p) {
+ private void bindLargeIcon(RemoteViews contentView, @NonNull StandardTemplateParams p,
+ @NonNull TemplateBindResult result) {
if (mN.mLargeIcon == null && mN.largeIcon != null) {
mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon);
}
boolean showLargeIcon = mN.mLargeIcon != null && !p.hideLargeIcon;
+ calculateLargeIconDimens(showLargeIcon, result);
if (showLargeIcon) {
+ contentView.setViewLayoutWidth(R.id.right_icon,
+ result.mRightIconWidthDp, TypedValue.COMPLEX_UNIT_DIP);
contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
processLargeLegacyIcon(mN.mLargeIcon, contentView, p);
@@ -5153,7 +5193,6 @@ public class Notification implements Parcelable
// visibility) is used by NotificationGroupingUtil to set the visibility.
contentView.setImageViewIcon(R.id.right_icon, null);
}
- return showLargeIcon;
}
private void bindNotificationHeader(RemoteViews contentView, StandardTemplateParams p) {
@@ -5356,8 +5395,9 @@ public class Notification implements Parcelable
final boolean snoozeEnabled = mContext.getContentResolver() != null
&& (Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
- big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
- snoozeEnabled ? 0 : R.dimen.notification_content_margin);
+ int bottomMarginDimen = snoozeEnabled ? 0 : R.dimen.notification_content_margin;
+ big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
+ RemoteViews.MARGIN_BOTTOM, bottomMarginDimen);
}
private static List<Notification.Action> filterOutContextualActions(
@@ -5389,7 +5429,8 @@ public class Notification implements Parcelable
if (N > 0) {
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
big.setViewVisibility(R.id.actions, View.VISIBLE);
- big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target, 0);
+ big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
+ RemoteViews.MARGIN_BOTTOM, 0);
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
for (int i=0; i<N; i++) {
Action action = nonContextualActions.get(i);
@@ -7788,8 +7829,9 @@ public class Notification implements Parcelable
// also update the end margin if there is an image
// NOTE: This template doesn't support moving this icon to the left, so we don't
// need to fully apply the MarginSet
- contentView.setViewLayoutMarginEnd(R.id.notification_messaging,
- bindResult.mHeadingExtraMarginSet.getValue());
+ contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END,
+ bindResult.mHeadingExtraMarginSet.getDpValue(),
+ TypedValue.COMPLEX_UNIT_DIP);
}
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
mBuilder.isColorized(p)
@@ -8613,7 +8655,8 @@ public class Notification implements Parcelable
if (mBuilder.mN.hasLargeIcon()) {
endMargin = R.dimen.notification_media_image_margin_end;
}
- view.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
+ view.setViewLayoutMarginDimen(R.id.notification_main_column,
+ RemoteViews.MARGIN_END, endMargin);
return view;
}
@@ -8650,8 +8693,8 @@ public class Notification implements Parcelable
private void handleImage(RemoteViews contentView) {
if (mBuilder.mN.hasLargeIcon()) {
- contentView.setViewLayoutMarginEndDimen(R.id.line1, 0);
- contentView.setViewLayoutMarginEndDimen(R.id.text, 0);
+ contentView.setViewLayoutMarginDimen(R.id.line1, RemoteViews.MARGIN_END, 0);
+ contentView.setViewLayoutMarginDimen(R.id.text, RemoteViews.MARGIN_END, 0);
}
}
@@ -8787,7 +8830,8 @@ public class Notification implements Parcelable
// also update the end margin to account for the large icon or expander
Resources resources = mBuilder.mContext.getResources();
result.mTitleMarginSet.applyToView(remoteViews, R.id.notification_main_column,
- resources.getDimensionPixelOffset(R.dimen.notification_content_margin_end));
+ resources.getDimension(R.dimen.notification_content_margin_end)
+ / resources.getDisplayMetrics().density);
}
}
@@ -11025,6 +11069,7 @@ public class Notification implements Parcelable
*/
private static class TemplateBindResult {
boolean mRightIconVisible;
+ float mRightIconWidthDp;
/**
* The margin end that needs to be added to the heading so that it won't overlap
@@ -11049,11 +11094,13 @@ public class Notification implements Parcelable
*/
public final MarginSet mTitleMarginSet = new MarginSet();
- public void setRightIconState(boolean visible, int marginEndIfVisible, int expanderSize) {
+ public void setRightIconState(boolean visible, float widthDp,
+ float marginEndDpIfVisible, float expanderSizeDp) {
mRightIconVisible = visible;
- mHeadingExtraMarginSet.setValues(0, marginEndIfVisible);
- mHeadingFullMarginSet.setValues(expanderSize, marginEndIfVisible + expanderSize);
- mTitleMarginSet.setValues(0, marginEndIfVisible + expanderSize);
+ mRightIconWidthDp = widthDp;
+ mHeadingExtraMarginSet.setValues(0, marginEndDpIfVisible);
+ mHeadingFullMarginSet.setValues(expanderSizeDp, marginEndDpIfVisible + expanderSizeDp);
+ mTitleMarginSet.setValues(0, marginEndDpIfVisible + expanderSizeDp);
}
/**
@@ -11062,10 +11109,10 @@ public class Notification implements Parcelable
* left_icon and adjust the margins, and to undo that change as well.
*/
private class MarginSet {
- private int mValueIfGone;
- private int mValueIfVisible;
+ private float mValueIfGone;
+ private float mValueIfVisible;
- public void setValues(int valueIfGone, int valueIfVisible) {
+ public void setValues(float valueIfGone, float valueIfVisible) {
mValueIfGone = valueIfGone;
mValueIfVisible = valueIfVisible;
}
@@ -11075,22 +11122,26 @@ public class Notification implements Parcelable
}
public void applyToView(@NonNull RemoteViews views, @IdRes int viewId,
- @Px int extraMargin) {
- final int marginEnd = getValue() + extraMargin;
+ float extraMarginDp) {
+ final float marginEndDp = getDpValue() + extraMarginDp;
if (viewId == R.id.notification_header) {
- views.setInt(R.id.notification_header, "setTopLineExtraMarginEnd", marginEnd);
+ views.setFloat(R.id.notification_header,
+ "setTopLineExtraMarginEndDp", marginEndDp);
} else {
- views.setViewLayoutMarginEnd(viewId, marginEnd);
+ views.setViewLayoutMargin(viewId, RemoteViews.MARGIN_END,
+ marginEndDp, TypedValue.COMPLEX_UNIT_DIP);
}
if (mRightIconVisible) {
views.setIntTag(viewId, R.id.tag_margin_end_when_icon_visible,
- mValueIfVisible + extraMargin);
+ TypedValue.createComplexDimension(
+ mValueIfVisible + extraMarginDp, TypedValue.COMPLEX_UNIT_DIP));
views.setIntTag(viewId, R.id.tag_margin_end_when_icon_gone,
- mValueIfGone + extraMargin);
+ TypedValue.createComplexDimension(
+ mValueIfGone + extraMarginDp, TypedValue.COMPLEX_UNIT_DIP));
}
}
- public int getValue() {
+ public float getDpValue() {
return mRightIconVisible ? mValueIfVisible : mValueIfGone;
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index ae1c89468b18..2ce0e877aa9f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -30,7 +30,6 @@ import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.job.JobSchedulerFrameworkInitializer;
import android.app.prediction.AppPredictionManager;
-import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
import android.app.search.SearchUiManager;
import android.app.slice.SliceManager;
@@ -1291,14 +1290,6 @@ public final class SystemServiceRegistry {
return new RoleManager(ctx.getOuterContext());
}});
- registerService(Context.ROLE_CONTROLLER_SERVICE, RoleControllerManager.class,
- new CachedServiceFetcher<RoleControllerManager>() {
- @Override
- public RoleControllerManager createService(ContextImpl ctx)
- throws ServiceNotFoundException {
- return new RoleControllerManager(ctx.getOuterContext());
- }});
-
registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class,
new CachedServiceFetcher<DynamicSystemManager>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 259c1a16d85a..806cb496c4c3 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11241,6 +11241,7 @@ public class DevicePolicyManager {
* {@code android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS} or the caller is
* not {@link UserHandle#SYSTEM_USER}
*/
+ @TestApi
public void forceUpdateUserSetupComplete() {
try {
mService.forceUpdateUserSetupComplete();
diff --git a/core/java/android/app/admin/DevicePolicySafetyChecker.java b/core/java/android/app/admin/DevicePolicySafetyChecker.java
index 1f8a9335b9ac..b1a80c55cf1e 100644
--- a/core/java/android/app/admin/DevicePolicySafetyChecker.java
+++ b/core/java/android/app/admin/DevicePolicySafetyChecker.java
@@ -18,6 +18,8 @@ package android.app.admin;
import android.annotation.NonNull;
import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
+import com.android.internal.os.IResultReceiver;
+
/**
* Interface responsible to check if a {@link DevicePolicyManager} API can be safely executed.
*
@@ -28,9 +30,7 @@ public interface DevicePolicySafetyChecker {
/**
* Returns whether the given {@code operation} can be safely executed at the moment.
*/
- default boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation) {
- return true;
- }
+ boolean isDevicePolicyOperationSafe(@DevicePolicyOperation int operation);
/**
* Returns a new exception for when the given {@code operation} cannot be safely executed.
@@ -39,4 +39,13 @@ public interface DevicePolicySafetyChecker {
default UnsafeStateException newUnsafeStateException(@DevicePolicyOperation int operation) {
return new UnsafeStateException(operation);
}
+
+ /**
+ * Called when a request was made to factory reset the device, so it can be delayed if it's not
+ * safe to proceed.
+ *
+ * @param callback callback whose {@code send()} method must be called when it's safe to factory
+ * reset.
+ */
+ void onFactoryReset(IResultReceiver callback);
}
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 8dde2c55d7d3..ba1f61290631 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -20,8 +20,6 @@ import android.Manifest;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
-import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
@@ -48,8 +46,6 @@ import java.util.function.Consumer;
*
* @hide
*/
-@SystemService(Context.ROLE_CONTROLLER_SERVICE)
-@TestApi
public class RoleControllerManager {
private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
@@ -199,32 +195,11 @@ public class RoleControllerManager {
}
/**
- * @see RoleControllerService#onIsApplicationQualifiedForRole(String, String)
- *
- * @deprecated Use {@link #isApplicationVisibleForRole(String, String, Executor, Consumer)}
- * instead.
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- public void isApplicationQualifiedForRole(@NonNull String roleName, @NonNull String packageName,
- @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
- AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
- AndroidFuture<Bundle> future = new AndroidFuture<>();
- service.isApplicationQualifiedForRole(roleName, packageName,
- new RemoteCallback(future::complete));
- return future;
- });
- propagateCallback(operation, "isApplicationQualifiedForRole", executor, callback);
- }
-
- /**
* @see RoleControllerService#onIsApplicationVisibleForRole(String, String)
*
* @hide
*/
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @TestApi
public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
@@ -242,7 +217,6 @@ public class RoleControllerManager {
* @hide
*/
@RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
- @TestApi
public void isRoleVisible(@NonNull String roleName,
@NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
AndroidFuture<Bundle> operation = mRemoteService.postAsync(service -> {
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 8b2e07b09701..9ddd5bef5c6f 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -174,6 +174,9 @@ public final class RoleManager {
@NonNull
private final Object mListenersLock = new Object();
+ @NonNull
+ private final RoleControllerManager mRoleControllerManager;
+
/**
* @hide
*/
@@ -181,6 +184,7 @@ public final class RoleManager {
mContext = context;
mService = IRoleManager.Stub.asInterface(ServiceManager.getServiceOrThrow(
Context.ROLE_SERVICE));
+ mRoleControllerManager = new RoleControllerManager(context);
}
/**
@@ -676,6 +680,44 @@ public final class RoleManager {
}
}
+ /**
+ * Check whether a role should be visible to user.
+ *
+ * @param roleName name of the role to check for
+ * @param executor the executor to execute callback on
+ * @param callback the callback to receive whether the role should be visible to user
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @SystemApi
+ public void isRoleVisible(@NonNull String roleName,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+ mRoleControllerManager.isRoleVisible(roleName, executor, callback);
+ }
+
+ /**
+ * Check whether an application is visible for a role.
+ *
+ * While an application can be qualified for a role, it can still stay hidden from user (thus
+ * not visible). If an application is visible for a role, we may show things related to the role
+ * for it, e.g. showing an entry pointing to the role settings in its application info page.
+ *
+ * @param roleName the name of the role to check for
+ * @param packageName the package name of the application to check for
+ * @param executor the executor to execute callback on
+ * @param callback the callback to receive whether the application is visible for the role
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @SystemApi
+ public void isApplicationVisibleForRole(@NonNull String roleName, @NonNull String packageName,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+ mRoleControllerManager.isApplicationVisibleForRole(roleName, packageName, executor,
+ callback);
+ }
+
private static class OnRoleHoldersChangedListenerDelegate
extends IOnRoleHoldersChangedListener.Stub {
diff --git a/core/java/android/app/time/LocationTimeZoneManager.java b/core/java/android/app/time/LocationTimeZoneManager.java
index d909c0cb1eba..71a800f2085e 100644
--- a/core/java/android/app/time/LocationTimeZoneManager.java
+++ b/core/java/android/app/time/LocationTimeZoneManager.java
@@ -40,17 +40,58 @@ public final class LocationTimeZoneManager {
public static final String SHELL_COMMAND_SERVICE_NAME = "location_time_zone_manager";
/**
- * Shell command that starts the service (after stop).
+ * A shell command that starts the service (after stop).
*/
public static final String SHELL_COMMAND_START = "start";
/**
- * Shell command that stops the service.
+ * A shell command that stops the service.
*/
public static final String SHELL_COMMAND_STOP = "stop";
/**
- * Shell command that sends test commands to a provider
+ * A shell command that can put providers into different modes. Takes effect next time the
+ * service is started.
+ */
+ public static final String SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE =
+ "set_provider_mode_override";
+
+ /**
+ * The default provider mode.
+ * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
+ */
+ public static final String PROVIDER_MODE_OVERRIDE_NONE = "none";
+
+ /**
+ * The "simulated" provider mode.
+ * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
+ */
+ public static final String PROVIDER_MODE_OVERRIDE_SIMULATED = "simulated";
+
+ /**
+ * The "disabled" provider mode (equivalent to there being no provider configured).
+ * For use with {@link #SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE}.
+ */
+ public static final String PROVIDER_MODE_OVERRIDE_DISABLED = "disabled";
+
+ /**
+ * A shell command that tells the service to record state information during tests. The next
+ * argument value is "true" or "false".
+ */
+ public static final String SHELL_COMMAND_RECORD_PROVIDER_STATES = "record_provider_states";
+
+ /**
+ * A shell command that tells the service to dump its current state.
+ */
+ public static final String SHELL_COMMAND_DUMP_STATE = "dump_state";
+
+ /**
+ * Option for {@link #SHELL_COMMAND_DUMP_STATE} that tells it to dump state as a binary proto.
+ */
+ public static final String DUMP_STATE_OPTION_PROTO = "--proto";
+
+ /**
+ * A shell command that sends test commands to a provider
*/
public static final String SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND =
"send_provider_test_command";
@@ -88,35 +129,6 @@ public final class LocationTimeZoneManager {
*/
public static final String SIMULATED_PROVIDER_TEST_COMMAND_UNCERTAIN = "uncertain";
- private static final String SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PREFIX =
- "persist.sys.geotz.";
-
- /**
- * The name of the system property that can be used to set the primary provider into test mode
- * (value = {@link #SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED}) or disabled (value = {@link
- * #SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED}).
- */
- public static final String SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PRIMARY =
- SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PREFIX + PRIMARY_PROVIDER_NAME;
-
- /**
- * The name of the system property that can be used to set the secondary provider into test mode
- * (value = {@link #SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED}) or disabled (value = {@link
- * #SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED}).
- */
- public static final String SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_SECONDARY =
- SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PREFIX + SECONDARY_PROVIDER_NAME;
-
- /**
- * The value of the provider mode system property to put a provider into test mode.
- */
- public static final String SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED = "simulated";
-
- /**
- * The value of the provider mode system property to put a provider into disabled mode.
- */
- public static final String SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED = "disabled";
-
private LocationTimeZoneManager() {
// No need to instantiate.
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index e0b7ffed1b36..ee718b35d4c5 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -29,11 +29,69 @@ import android.content.Context;
@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
public interface TimeZoneDetector {
- /** @hide */
+ /**
+ * The name of the service for shell commands.
+ * @hide
+ */
+ String SHELL_COMMAND_SERVICE_NAME = "time_zone_detector";
+
+ /**
+ * A shell command that prints the current "auto time zone detection" global setting value.
+ * @hide
+ */
+ String SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED = "is_auto_detection_enabled";
+
+ /**
+ * A shell command that sets the current "auto time zone detection" global setting value.
+ * @hide
+ */
+ String SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED = "set_auto_detection_enabled";
+
+ /**
+ * A shell command that prints whether the geolocation-based time zone detection feature is
+ * supported on the device.
+ * @hide
+ */
+ String SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED = "is_geo_detection_supported";
+
+ /**
+ * A shell command that prints the current user's "location enabled" setting.
+ * @hide
+ */
+ String SHELL_COMMAND_IS_LOCATION_ENABLED = "is_location_enabled";
+
+ /**
+ * A shell command that prints the current user's "location-based time zone detection enabled"
+ * setting.
+ * @hide
+ */
+ String SHELL_COMMAND_IS_GEO_DETECTION_ENABLED = "is_geo_detection_enabled";
+
+ /**
+ * A shell command that sets the current user's "location-based time zone detection enabled"
+ * setting.
+ * @hide
+ */
+ String SHELL_COMMAND_SET_GEO_DETECTION_ENABLED = "set_geo_detection_enabled";
+
+ /**
+ * A shell command that injects a geolocation time zone suggestion (as if from the
+ * location_time_zone_manager).
+ * @hide
+ */
String SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE = "suggest_geo_location_time_zone";
- /** @hide */
+
+ /**
+ * A shell command that injects a manual time zone suggestion (as if from the SettingsUI or
+ * similar).
+ * @hide
+ */
String SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE = "suggest_manual_time_zone";
- /** @hide */
+
+ /**
+ * A shell command that injects a telephony time zone suggestion (as if from the phone app).
+ * @hide
+ */
String SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE = "suggest_telephony_time_zone";
/**
diff --git a/core/java/android/apphibernation/OWNERS b/core/java/android/apphibernation/OWNERS
new file mode 100644
index 000000000000..587c719f5587
--- /dev/null
+++ b/core/java/android/apphibernation/OWNERS
@@ -0,0 +1,2 @@
+kevhan@google.com
+rajekumar@google.com
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 29ffa0b70313..33f960732be9 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4821,16 +4821,6 @@ public abstract class Context {
public static final String ROLE_SERVICE = "role";
/**
- * Official published name of the (internal) role controller service.
- *
- * @see #getSystemService(String)
- * @see android.app.role.RoleControllerService
- *
- * @hide
- */
- public static final String ROLE_CONTROLLER_SERVICE = "role_controller";
-
- /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.hardware.camera2.CameraManager} for interacting with
* camera devices.
diff --git a/core/java/android/hardware/biometrics/OWNERS b/core/java/android/hardware/biometrics/OWNERS
index 33527f824827..2065ffacca7c 100644
--- a/core/java/android/hardware/biometrics/OWNERS
+++ b/core/java/android/hardware/biometrics/OWNERS
@@ -1,3 +1,8 @@
# Bug component: 879035
+curtislb@google.com
+ilyamaty@google.com
jaggies@google.com
+joshmccloskey@google.com
+kchyn@google.com
+
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a4e573876218..582570e63d54 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -568,11 +568,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @param cancel an object that can be used to cancel enrollment
* @param userId the user to whom this fingerprint will belong to
* @param callback an object to receive enrollment events
+ * @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics
+ * should be logged.
* @hide
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
- EnrollmentCallback callback) {
+ EnrollmentCallback callback, boolean shouldLogMetrics) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
@@ -593,7 +595,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
try {
mEnrollmentCallback = callback;
mService.enroll(mToken, hardwareAuthToken, userId, mServiceReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), shouldLogMetrics);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 64abbea12de0..ac026c796b51 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -77,7 +77,7 @@ interface IFingerprintService {
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
- String opPackageName);
+ String opPackageName, boolean shouldLogMetrics);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
diff --git a/core/java/android/hardware/fingerprint/OWNERS b/core/java/android/hardware/fingerprint/OWNERS
index dcead40d482d..e55b8c564ddb 100644
--- a/core/java/android/hardware/fingerprint/OWNERS
+++ b/core/java/android/hardware/fingerprint/OWNERS
@@ -1,3 +1,8 @@
# Bug component: 114777
+curtislb@google.com
+ilyamaty@google.com
jaggies@google.com
+joshmccloskey@google.com
+kchyn@google.com
+
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index bf25602041cf..f41306301d42 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -45,8 +45,8 @@ import com.android.internal.util.IndentingPrintWriter;
import libcore.util.EmptyArray;
import java.io.CharArrayWriter;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ProtocolException;
@@ -162,7 +162,7 @@ public class NetworkStatsHistory implements Parcelable {
out.writeLong(totalBytes);
}
- public NetworkStatsHistory(DataInputStream in) throws IOException {
+ public NetworkStatsHistory(DataInput in) throws IOException {
final int version = in.readInt();
switch (version) {
case VERSION_INIT: {
@@ -204,7 +204,7 @@ public class NetworkStatsHistory implements Parcelable {
}
}
- public void writeToStream(DataOutputStream out) throws IOException {
+ public void writeToStream(DataOutput out) throws IOException {
out.writeInt(VERSION_ADD_ACTIVE);
out.writeLong(bucketDuration);
writeVarLongArray(out, bucketStart, bucketCount);
@@ -768,7 +768,7 @@ public class NetworkStatsHistory implements Parcelable {
*/
public static class DataStreamUtils {
@Deprecated
- public static long[] readFullLongArray(DataInputStream in) throws IOException {
+ public static long[] readFullLongArray(DataInput in) throws IOException {
final int size = in.readInt();
if (size < 0) throw new ProtocolException("negative array size");
final long[] values = new long[size];
@@ -781,7 +781,7 @@ public class NetworkStatsHistory implements Parcelable {
/**
* Read variable-length {@link Long} using protobuf-style approach.
*/
- public static long readVarLong(DataInputStream in) throws IOException {
+ public static long readVarLong(DataInput in) throws IOException {
int shift = 0;
long result = 0;
while (shift < 64) {
@@ -797,7 +797,7 @@ public class NetworkStatsHistory implements Parcelable {
/**
* Write variable-length {@link Long} using protobuf-style approach.
*/
- public static void writeVarLong(DataOutputStream out, long value) throws IOException {
+ public static void writeVarLong(DataOutput out, long value) throws IOException {
while (true) {
if ((value & ~0x7FL) == 0) {
out.writeByte((int) value);
@@ -809,7 +809,7 @@ public class NetworkStatsHistory implements Parcelable {
}
}
- public static long[] readVarLongArray(DataInputStream in) throws IOException {
+ public static long[] readVarLongArray(DataInput in) throws IOException {
final int size = in.readInt();
if (size == -1) return null;
if (size < 0) throw new ProtocolException("negative array size");
@@ -820,7 +820,7 @@ public class NetworkStatsHistory implements Parcelable {
return values;
}
- public static void writeVarLongArray(DataOutputStream out, long[] values, int size)
+ public static void writeVarLongArray(DataOutput out, long[] values, int size)
throws IOException {
if (values == null) {
out.writeInt(-1);
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index c014ef682a24..0326b72ece7c 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1463,8 +1463,7 @@ public final class FileUtils {
Uri uri = MediaStore.scanFile(resolver, realFile);
if (uri != null) {
Bundle opts = new Bundle();
- // TODO(b/158465539): Use API constant
- opts.putBoolean("android.provider.extra.ACCEPT_ORIGINAL_MEDIA_FORMAT", true);
+ opts.putBoolean(MediaStore.EXTRA_ACCEPT_ORIGINAL_MEDIA_FORMAT, true);
AssetFileDescriptor afd = resolver.openTypedAssetFileDescriptor(uri, "*/*", opts);
Log.i(TAG, "Changed to modern format dataSource for: " + realFile);
return afd.getFileDescriptor();
diff --git a/core/java/android/service/notification/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java
index c945c2d64519..6fdfaabb009b 100644
--- a/core/java/android/service/notification/NotificationListenerFilter.java
+++ b/core/java/android/service/notification/NotificationListenerFilter.java
@@ -17,6 +17,7 @@ package android.service.notification;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import android.os.Parcel;
@@ -35,7 +36,8 @@ public class NotificationListenerFilter implements Parcelable {
public NotificationListenerFilter() {
mAllowedNotificationTypes = FLAG_FILTER_TYPE_CONVERSATIONS
| FLAG_FILTER_TYPE_ALERTING
- | FLAG_FILTER_TYPE_SILENT;
+ | FLAG_FILTER_TYPE_SILENT
+ | FLAG_FILTER_TYPE_ONGOING;
mDisallowedPackages = new ArraySet<>();
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index ccde0bcf71c3..f79b59fe5432 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -242,6 +242,16 @@ public abstract class NotificationListenerService extends Service {
public @interface NotificationCancelReason{};
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "FLAG_FILTER_TYPE_" }, value = {
+ FLAG_FILTER_TYPE_CONVERSATIONS,
+ FLAG_FILTER_TYPE_ALERTING,
+ FLAG_FILTER_TYPE_SILENT,
+ FLAG_FILTER_TYPE_ONGOING
+ })
+ public @interface NotificationFilterTypes {}
+ /**
* A flag value indicating that this notification listener can see conversation type
* notifications.
* @hide
@@ -257,6 +267,12 @@ public abstract class NotificationListenerService extends Service {
* @hide
*/
public static final int FLAG_FILTER_TYPE_SILENT = 4;
+ /**
+ * A flag value indicating that this notification listener can see important
+ * ( > {@link NotificationManager#IMPORTANCE_MIN}) ongoing type notifications.
+ * @hide
+ */
+ public static final int FLAG_FILTER_TYPE_ONGOING = 8;
/**
* The full trim of the StatusBarNotification including all its features.
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 46a5caf176b7..e934fa483ebe 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -22,9 +22,9 @@ import static android.Manifest.permission.RECORD_AUDIO;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
@@ -41,6 +41,7 @@ import android.media.AudioFormat;
import android.media.permission.Identity;
import android.os.AsyncTask;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -78,6 +79,7 @@ public class AlwaysOnHotwordDetector {
* No further interaction should be performed with the detector that returns this availability.
*/
public static final int STATE_HARDWARE_UNAVAILABLE = -2;
+
/**
* Indicates that recognition for the given keyphrase is not supported.
* No further interaction should be performed with the detector that returns this availability.
@@ -88,11 +90,13 @@ public class AlwaysOnHotwordDetector {
*/
@Deprecated
public static final int STATE_KEYPHRASE_UNSUPPORTED = -1;
+
/**
* Indicates that the given keyphrase is not enrolled.
* The caller may choose to begin an enrollment flow for the keyphrase.
*/
public static final int STATE_KEYPHRASE_UNENROLLED = 1;
+
/**
* Indicates that the given keyphrase is currently enrolled and it's possible to start
* recognition for it.
@@ -100,6 +104,14 @@ public class AlwaysOnHotwordDetector {
public static final int STATE_KEYPHRASE_ENROLLED = 2;
/**
+ * Indicates that the availability state of the active keyphrase can't be known due to an error.
+ *
+ * <p>NOTE: No further interaction should be performed with the detector that returns this
+ * state, it would be better to create {@link AlwaysOnHotwordDetector} again.
+ */
+ public static final int STATE_ERROR = 3;
+
+ /**
* Indicates that the detector isn't ready currently.
*/
private static final int STATE_NOT_READY = 0;
@@ -122,11 +134,13 @@ public class AlwaysOnHotwordDetector {
* @hide
*/
public static final int RECOGNITION_FLAG_NONE = 0;
+
/**
* Recognition flag for {@link #startRecognition(int)} that indicates
* whether the trigger audio for hotword needs to be captured.
*/
public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 0x1;
+
/**
* Recognition flag for {@link #startRecognition(int)} that indicates
* whether the recognition should keep going on even after the keyphrase triggers.
@@ -174,6 +188,7 @@ public class AlwaysOnHotwordDetector {
*/
public static final int RECOGNITION_MODE_VOICE_TRIGGER
= SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
+
/**
* User identification performed with the keyphrase recognition.
* Returned by {@link #getSupportedRecognitionModes()}
@@ -249,6 +264,7 @@ public class AlwaysOnHotwordDetector {
private final Object mLock = new Object();
private final Handler mHandler;
private final IBinder mBinder = new Binder();
+ private final int mTargetSdkVersion;
private int mAvailability = STATE_NOT_READY;
@@ -401,8 +417,10 @@ public class AlwaysOnHotwordDetector {
* @see AlwaysOnHotwordDetector#STATE_HARDWARE_UNAVAILABLE
* @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_UNENROLLED
* @see AlwaysOnHotwordDetector#STATE_KEYPHRASE_ENROLLED
+ * @see AlwaysOnHotwordDetector#STATE_ERROR
*/
public abstract void onAvailabilityChanged(int status);
+
/**
* Called when the keyphrase is spoken.
* This implicitly stops listening for the keyphrase once it's detected.
@@ -414,16 +432,19 @@ public class AlwaysOnHotwordDetector {
* {@link AlwaysOnHotwordDetector#startRecognition(int)}.
*/
public abstract void onDetected(@NonNull EventPayload eventPayload);
+
/**
* Called when the detection fails due to an error.
*/
public abstract void onError();
+
/**
* Called when the recognition is paused temporarily for some reason.
* This is an informational callback, and the clients shouldn't be doing anything here
* except showing an indication on their UI if they have to.
*/
public abstract void onRecognitionPaused();
+
/**
* Called when the recognition is resumed after it was temporarily paused.
* This is an informational callback, and the clients shouldn't be doing anything here
@@ -437,11 +458,12 @@ public class AlwaysOnHotwordDetector {
* @param locale The java locale for the detector.
* @param callback A non-null Callback for receiving the recognition events.
* @param modelManagementService A service that allows management of sound models.
+ * @param targetSdkVersion The target SDK version.
* @hide
*/
public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
- IVoiceInteractionManagerService modelManagementService) {
+ IVoiceInteractionManagerService modelManagementService, int targetSdkVersion) {
mText = text;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
@@ -449,6 +471,7 @@ public class AlwaysOnHotwordDetector {
mHandler = new MyHandler();
mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService;
+ mTargetSdkVersion = targetSdkVersion;
try {
Identity identity = new Identity();
identity.packageName = ActivityThread.currentOpPackageName();
@@ -469,7 +492,7 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if the keyphrase itself isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
+ * @throws IllegalStateException if the detector is in an invalid or error state.
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@@ -481,9 +504,9 @@ public class AlwaysOnHotwordDetector {
}
private int getSupportedRecognitionModesLocked() {
- if (mAvailability == STATE_INVALID) {
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
throw new IllegalStateException(
- "getSupportedRecognitionModes called on an invalid detector");
+ "getSupportedRecognitionModes called on an invalid detector or error state");
}
// This method only makes sense if we can actually support a recognition.
@@ -541,7 +564,7 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
+ * @throws IllegalStateException if the detector is in an invalid or error state.
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@@ -549,8 +572,9 @@ public class AlwaysOnHotwordDetector {
public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
synchronized (mLock) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("startRecognition called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "startRecognition called on an invalid detector or error state");
}
// Check if we can start/stop a recognition.
@@ -572,7 +596,7 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if the recognition isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
+ * @throws IllegalStateException if the detector is in an invalid or error state.
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@@ -580,8 +604,9 @@ public class AlwaysOnHotwordDetector {
public boolean stopRecognition() {
if (DBG) Slog.d(TAG, "stopRecognition()");
synchronized (mLock) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("stopRecognition called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "stopRecognition called on an invalid detector or error state");
}
// Check if we can start/stop a recognition.
@@ -610,6 +635,9 @@ public class AlwaysOnHotwordDetector {
* - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
* - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
* if API is not supported by HAL
+ * @throws IllegalStateException if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
public int setParameter(@ModelParams int modelParam, int value) {
@@ -618,8 +646,9 @@ public class AlwaysOnHotwordDetector {
}
synchronized (mLock) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("setParameter called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "setParameter called on an invalid detector or error state");
}
return setParameterLocked(modelParam, value);
@@ -638,6 +667,9 @@ public class AlwaysOnHotwordDetector {
*
* @param modelParam {@link ModelParams}
* @return value of parameter
+ * @throws IllegalStateException if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
public int getParameter(@ModelParams int modelParam) {
@@ -646,8 +678,9 @@ public class AlwaysOnHotwordDetector {
}
synchronized (mLock) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("getParameter called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "getParameter called on an invalid detector or error state");
}
return getParameterLocked(modelParam);
@@ -663,6 +696,9 @@ public class AlwaysOnHotwordDetector {
*
* @param modelParam {@link ModelParams}
* @return supported range of parameter, null if not supported
+ * @throws IllegalStateException if the detector is in an invalid or error state.
+ * This may happen if another detector has been instantiated or the
+ * {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD})
@Nullable
@@ -672,8 +708,9 @@ public class AlwaysOnHotwordDetector {
}
synchronized (mLock) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("queryParameter called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "queryParameter called on an invalid detector or error state");
}
return queryParameterLocked(modelParam);
@@ -735,7 +772,7 @@ public class AlwaysOnHotwordDetector {
* @throws UnsupportedOperationException if managing they keyphrase isn't supported.
* Callers should only call this method after a supported state callback on
* {@link Callback#onAvailabilityChanged(int)} to avoid this exception.
- * @throws IllegalStateException if the detector is in an invalid state.
+ * @throws IllegalStateException if the detector is in an invalid or error state.
* This may happen if another detector has been instantiated or the
* {@link VoiceInteractionService} hosting this detector has been shut down.
*/
@@ -748,8 +785,9 @@ public class AlwaysOnHotwordDetector {
}
private Intent getManageIntentLocked(@KeyphraseEnrollmentInfo.ManageActions int action) {
- if (mAvailability == STATE_INVALID) {
- throw new IllegalStateException("getManageIntent called on an invalid detector");
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_ERROR) {
+ throw new IllegalStateException(
+ "getManageIntent called on an invalid detector or error state");
}
// This method only makes sense if we can actually support a recognition.
@@ -783,8 +821,10 @@ public class AlwaysOnHotwordDetector {
void onSoundModelsChanged() {
synchronized (mLock) {
if (mAvailability == STATE_INVALID
- || mAvailability == STATE_HARDWARE_UNAVAILABLE) {
- Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config");
+ || mAvailability == STATE_HARDWARE_UNAVAILABLE
+ || mAvailability == STATE_ERROR) {
+ Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config"
+ + " or in the error state");
return;
}
@@ -794,7 +834,16 @@ public class AlwaysOnHotwordDetector {
// The availability change callback should ensure that the client starts recognition
// again if needed.
if (mAvailability == STATE_KEYPHRASE_ENROLLED) {
- stopRecognitionLocked();
+ try {
+ stopRecognitionLocked();
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Failed to Stop the recognition", e);
+ if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
+ throw e;
+ }
+ updateAndNotifyStateChangedLocked(STATE_ERROR);
+ return;
+ }
}
// Execute a refresh availability task - which should then notify of a change.
@@ -890,6 +939,15 @@ public class AlwaysOnHotwordDetector {
}
}
+ private void updateAndNotifyStateChangedLocked(int availability) {
+ if (DBG) {
+ Slog.d(TAG, "Hotword availability changed from " + mAvailability
+ + " -> " + availability);
+ }
+ mAvailability = availability;
+ notifyStateChangedLocked();
+ }
+
private void notifyStateChangedLocked() {
Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED);
message.arg1 = mAvailability;
@@ -976,25 +1034,30 @@ public class AlwaysOnHotwordDetector {
@Override
public Void doInBackground(Void... params) {
- int availability = internalGetInitialAvailability();
-
- synchronized (mLock) {
- if (availability == STATE_NOT_READY) {
- internalUpdateEnrolledKeyphraseMetadata();
- if (mKeyphraseMetadata != null) {
- availability = STATE_KEYPHRASE_ENROLLED;
- } else {
- availability = STATE_KEYPHRASE_UNENROLLED;
+ try {
+ int availability = internalGetInitialAvailability();
+
+ synchronized (mLock) {
+ if (availability == STATE_NOT_READY) {
+ internalUpdateEnrolledKeyphraseMetadata();
+ if (mKeyphraseMetadata != null) {
+ availability = STATE_KEYPHRASE_ENROLLED;
+ } else {
+ availability = STATE_KEYPHRASE_UNENROLLED;
+ }
}
+ updateAndNotifyStateChangedLocked(availability);
}
-
- if (DBG) {
- Slog.d(TAG, "Hotword availability changed from " + mAvailability
- + " -> " + availability);
+ } catch (SecurityException e) {
+ Slog.w(TAG, "Failed to refresh availability", e);
+ if (mTargetSdkVersion <= Build.VERSION_CODES.R) {
+ throw e;
+ }
+ synchronized (mLock) {
+ updateAndNotifyStateChangedLocked(STATE_ERROR);
}
- mAvailability = availability;
- notifyStateChangedLocked();
}
+
return null;
}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index fb03ed45113e..4aff695f1b47 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -325,7 +325,8 @@ public class VoiceInteractionService extends Service {
// Allow only one concurrent recognition via the APIs.
safelyShutdownHotwordDetector();
mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
- mKeyphraseEnrollmentInfo, mSystemService);
+ mKeyphraseEnrollmentInfo, mSystemService,
+ getApplicationContext().getApplicationInfo().targetSdkVersion);
}
return mHotwordDetector;
}
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 7f1ee302903b..19de396c4a4a 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -17,8 +17,14 @@
package android.util;
import android.annotation.AnyRes;
+import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.content.pm.ActivityInfo.Config;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Container for a dynamically typed data value. Primarily used with
* {@link android.content.res.Resources} for holding resource values.
@@ -95,6 +101,18 @@ public class TypedValue {
* defined below. */
public static final int COMPLEX_UNIT_MASK = 0xf;
+ /** @hide **/
+ @IntDef(prefix = "COMPLEX_UNIT_", value = {
+ COMPLEX_UNIT_PX,
+ COMPLEX_UNIT_DIP,
+ COMPLEX_UNIT_SP,
+ COMPLEX_UNIT_PT,
+ COMPLEX_UNIT_IN,
+ COMPLEX_UNIT_MM,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComplexDimensionUnit {}
+
/** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */
public static final int COMPLEX_UNIT_PX = 0;
/** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent
@@ -381,7 +399,7 @@ public class TypedValue {
* @return The complex floating point value multiplied by the appropriate
* metrics depending on its unit.
*/
- public static float applyDimension(int unit, float value,
+ public static float applyDimension(@ComplexDimensionUnit int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
@@ -417,6 +435,130 @@ public class TypedValue {
}
/**
+ * Construct a complex data integer. This validates the radix and the magnitude of the
+ * mantissa, and sets the {@link TypedValue#COMPLEX_MANTISSA_MASK} and
+ * {@link TypedValue#COMPLEX_RADIX_MASK} components as provided. The units are not set.
+ **
+ * @param mantissa an integer representing the mantissa.
+ * @param radix a radix option, e.g. {@link TypedValue#COMPLEX_RADIX_23p0}.
+ * @return A complex data integer representing the value.
+ * @hide
+ */
+ private static int createComplex(@IntRange(from = -0x800000, to = 0x7FFFFF) int mantissa,
+ int radix) {
+ if (mantissa < -0x800000 || mantissa >= 0x800000) {
+ throw new IllegalArgumentException("Magnitude of mantissa is too large: " + mantissa);
+ }
+ if (radix < TypedValue.COMPLEX_RADIX_23p0 || radix > TypedValue.COMPLEX_RADIX_0p23) {
+ throw new IllegalArgumentException("Invalid radix: " + radix);
+ }
+ return ((mantissa & TypedValue.COMPLEX_MANTISSA_MASK) << TypedValue.COMPLEX_MANTISSA_SHIFT)
+ | (radix << TypedValue.COMPLEX_RADIX_SHIFT);
+ }
+
+ /**
+ * Convert a base value to a complex data integer. This sets the {@link
+ * TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the
+ * data to create a floating point representation of the given value. The units are not set.
+ *
+ * <p>This is the inverse of {@link TypedValue#complexToFloat(int)}.
+ *
+ * @param value An integer value.
+ * @return A complex data integer representing the value.
+ * @hide
+ */
+ public static int intToComplex(int value) {
+ if (value < -0x800000 || value >= 0x800000) {
+ throw new IllegalArgumentException("Magnitude of the value is too large: " + value);
+ }
+ return createComplex(value, TypedValue.COMPLEX_RADIX_23p0);
+ }
+
+ /**
+ * Convert a base value to a complex data integer. This sets the {@link
+ * TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the
+ * data to create a floating point representation of the given value. The units are not set.
+ *
+ * <p>This is the inverse of {@link TypedValue#complexToFloat(int)}.
+ *
+ * @param value A floating point value.
+ * @return A complex data integer representing the value.
+ * @hide
+ */
+ public static int floatToComplex(@FloatRange(from = -0x800000, to = 0x7FFFFF) float value) {
+ // validate that the magnitude fits in this representation
+ if (value < (float) -0x800000 - .5f || value >= (float) 0x800000 - .5f) {
+ throw new IllegalArgumentException("Magnitude of the value is too large: " + value);
+ }
+ try {
+ // If there's no fraction, use integer representation, as that's clearer
+ if (value == (float) (int) value) {
+ return createComplex((int) value, TypedValue.COMPLEX_RADIX_23p0);
+ }
+ float absValue = Math.abs(value);
+ // If the magnitude is 0, we don't need any magnitude digits
+ if (absValue < 1f) {
+ return createComplex(Math.round(value * (1 << 23)), TypedValue.COMPLEX_RADIX_0p23);
+ }
+ // If the magnitude is less than 2^8, use 8 magnitude digits
+ if (absValue < (float) (1 << 8)) {
+ return createComplex(Math.round(value * (1 << 15)), TypedValue.COMPLEX_RADIX_8p15);
+ }
+ // If the magnitude is less than 2^16, use 16 magnitude digits
+ if (absValue < (float) (1 << 16)) {
+ return createComplex(Math.round(value * (1 << 7)), TypedValue.COMPLEX_RADIX_16p7);
+ }
+ // The magnitude requires all 23 digits
+ return createComplex(Math.round(value), TypedValue.COMPLEX_RADIX_23p0);
+ } catch (IllegalArgumentException ex) {
+ // Wrap exception so as to include the value argument in the message.
+ throw new IllegalArgumentException("Unable to convert value to complex: " + value, ex);
+ }
+ }
+
+ /**
+ * <p>Creates a complex data integer that stores a dimension value and units.
+ *
+ * <p>The resulting value can be passed to e.g.
+ * {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel
+ * value for the dimension.
+ *
+ * @param value the value of the dimension
+ * @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
+ * @return A complex data integer representing the value and units of the dimension.
+ * @hide
+ */
+ public static int createComplexDimension(
+ @IntRange(from = -0x800000, to = 0x7FFFFF) int value,
+ @ComplexDimensionUnit int units) {
+ if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) {
+ throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units);
+ }
+ return intToComplex(value) | units;
+ }
+
+ /**
+ * <p>Creates a complex data integer that stores a dimension value and units.
+ *
+ * <p>The resulting value can be passed to e.g.
+ * {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel
+ * value for the dimension.
+ *
+ * @param value the value of the dimension
+ * @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
+ * @return A complex data integer representing the value and units of the dimension.
+ * @hide
+ */
+ public static int createComplexDimension(
+ @FloatRange(from = -0x800000, to = 0x7FFFFF) float value,
+ @ComplexDimensionUnit int units) {
+ if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) {
+ throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units);
+ }
+ return floatToComplex(value) | units;
+ }
+
+ /**
* Converts a complex data value holding a fraction to its final floating
* point value. The given <var>data</var> must be structured as a
* {@link #TYPE_FRACTION}.
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 673ed0d8b95d..5ce4c50cc85c 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -156,14 +156,25 @@ public class NotificationHeaderView extends FrameLayout {
* Sets the extra margin at the end of the top line of left-aligned text + icons.
* This value will have the margin required to accommodate the expand button added to it.
*
- * @param extraMarginEnd extra margin
+ * @param extraMarginEnd extra margin in px
*/
- @RemotableViewMethod
public void setTopLineExtraMarginEnd(int extraMarginEnd) {
mTopLineView.setHeaderTextMarginEnd(extraMarginEnd + mHeadingEndMargin);
}
/**
+ * Sets the extra margin at the end of the top line of left-aligned text + icons.
+ * This value will have the margin required to accommodate the expand button added to it.
+ *
+ * @param extraMarginEndDp extra margin in dp
+ */
+ @RemotableViewMethod
+ public void setTopLineExtraMarginEndDp(float extraMarginEndDp) {
+ setTopLineExtraMarginEnd(
+ (int) (extraMarginEndDp * getResources().getDisplayMetrics().density));
+ }
+
+ /**
* Get the current margin end value for the header text.
* Add this to {@link #getTopLineBaseMarginEnd()} to get the total margin of the top line.
*
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 6d88d637dc24..482f2f07499d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -386,6 +386,16 @@ public interface WindowManager extends ViewManager {
* @hide
*/
int TRANSIT_KEYGUARD_UNOCCLUDE = 9;
+ /**
+ * The first slot for custom transition types. Callers (like Shell) can make use of custom
+ * transition types for dealing with special cases. These types are effectively ignored by
+ * Core and will just be passed along as part of TransitionInfo objects. An example is
+ * split-screen using a custom type for it's snap-to-dismiss action. By using a custom type,
+ * Shell can properly dispatch the results of that transition to the split-screen
+ * implementation.
+ * @hide
+ */
+ int TRANSIT_FIRST_CUSTOM = 10;
/**
* @hide
@@ -401,6 +411,7 @@ public interface WindowManager extends ViewManager {
TRANSIT_KEYGUARD_GOING_AWAY,
TRANSIT_KEYGUARD_OCCLUDE,
TRANSIT_KEYGUARD_UNOCCLUDE,
+ TRANSIT_FIRST_CUSTOM
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionType {}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index f057c1239e52..415b3a766d16 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -163,11 +163,13 @@ public class BaseInputConnection implements InputConnection {
}
/**
- * Default implementation calls {@link #finishComposingText()}.
+ * Default implementation calls {@link #finishComposingText()} and
+ * {@code setImeTemporarilyConsumesInput(false)}.
*/
@CallSuper
public void closeConnection() {
finishComposingText();
+ setImeTemporarilyConsumesInput(false);
}
/**
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 1cf25a77fa38..2df75f6570db 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -25,6 +25,7 @@ import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS;
import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -36,7 +37,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.InputType;
-import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.util.Printer;
import android.util.proto.ProtoOutputStream;
@@ -44,6 +44,7 @@ import android.view.View;
import android.view.autofill.AutofillId;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -563,8 +564,9 @@ public class EditorInfo implements InputType, Parcelable {
@VisibleForTesting
static final int MAX_INITIAL_SELECTION_LENGTH = MEMORY_EFFICIENT_TEXT_LENGTH / 2;
- @NonNull
- private InitialSurroundingText mInitialSurroundingText = new InitialSurroundingText();
+ @Nullable
+ private SurroundingText mInitialSurroundingText = null;
+
/**
* Editors may use this method to provide initial input text to IMEs. As the surrounding text
@@ -607,6 +609,12 @@ public class EditorInfo implements InputType, Parcelable {
public void setInitialSurroundingSubText(@NonNull CharSequence subText, int subTextStart) {
Objects.requireNonNull(subText);
+ // For privacy protection reason, we don't carry password inputs to IMEs.
+ if (isPasswordInputType(inputType)) {
+ mInitialSurroundingText = null;
+ return;
+ }
+
// Swap selection start and end if necessary.
final int subTextSelStart = initialSelStart > initialSelEnd
? initialSelEnd - subTextStart : initialSelStart - subTextStart;
@@ -616,23 +624,17 @@ public class EditorInfo implements InputType, Parcelable {
final int subTextLength = subText.length();
// Unknown or invalid selection.
if (subTextStart < 0 || subTextSelStart < 0 || subTextSelEnd > subTextLength) {
- mInitialSurroundingText = new InitialSurroundingText();
- return;
- }
-
- // For privacy protection reason, we don't carry password inputs to IMEs.
- if (isPasswordInputType(inputType)) {
- mInitialSurroundingText = new InitialSurroundingText();
+ mInitialSurroundingText = null;
return;
}
if (subTextLength <= MEMORY_EFFICIENT_TEXT_LENGTH) {
- mInitialSurroundingText = new InitialSurroundingText(subText, subTextSelStart,
- subTextSelEnd);
+ mInitialSurroundingText = new SurroundingText(subText, subTextSelStart,
+ subTextSelEnd, subTextStart);
return;
}
- trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd);
+ trimLongSurroundingText(subText, subTextSelStart, subTextSelEnd, subTextStart);
}
/**
@@ -651,8 +653,10 @@ public class EditorInfo implements InputType, Parcelable {
* @param subText The long text that needs to be trimmed.
* @param selStart The text offset of the start of the selection.
* @param selEnd The text offset of the end of the selection
+ * @param subTextStart The position that the input text got trimmed.
*/
- private void trimLongSurroundingText(CharSequence subText, int selStart, int selEnd) {
+ private void trimLongSurroundingText(CharSequence subText, int selStart, int selEnd,
+ int subTextStart) {
final int sourceSelLength = selEnd - selStart;
// When the selected text is too long, drop it.
final int newSelLength = (sourceSelLength > MAX_INITIAL_SELECTION_LENGTH)
@@ -702,10 +706,13 @@ public class EditorInfo implements InputType, Parcelable {
// obj.
newBeforeCursorHead = 0;
final int newSelHead = newBeforeCursorHead + newBeforeCursorLength;
- mInitialSurroundingText = new InitialSurroundingText(
- newInitialSurroundingText, newSelHead, newSelHead + newSelLength);
+ final int newOffset = subTextStart + selStart - newSelHead;
+ mInitialSurroundingText = new SurroundingText(
+ newInitialSurroundingText, newSelHead, newSelHead + newSelLength,
+ newOffset);
}
+
/**
* Get <var>length</var> characters of text before the current cursor position. May be
* {@code null} when the protocol is not supported.
@@ -720,7 +727,17 @@ public class EditorInfo implements InputType, Parcelable {
*/
@Nullable
public CharSequence getInitialTextBeforeCursor(int length, int flags) {
- return mInitialSurroundingText.getInitialTextBeforeCursor(length, flags);
+ if (mInitialSurroundingText == null) {
+ return null;
+ }
+
+ int selStart = Math.min(mInitialSurroundingText.getSelectionStart(),
+ mInitialSurroundingText.getSelectionEnd());
+ int n = Math.min(length, selStart);
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mInitialSurroundingText.getText().subSequence(selStart - n, selStart)
+ : TextUtils.substring(mInitialSurroundingText.getText(), selStart - n,
+ selStart);
}
/**
@@ -735,6 +752,10 @@ public class EditorInfo implements InputType, Parcelable {
*/
@Nullable
public CharSequence getInitialSelectedText(int flags) {
+ if (mInitialSurroundingText == null) {
+ return null;
+ }
+
// Swap selection start and end if necessary.
final int correctedTextSelStart = initialSelStart > initialSelEnd
? initialSelEnd : initialSelStart;
@@ -742,11 +763,21 @@ public class EditorInfo implements InputType, Parcelable {
? initialSelStart : initialSelEnd;
final int sourceSelLength = correctedTextSelEnd - correctedTextSelStart;
- if (initialSelStart < 0 || initialSelEnd < 0
- || mInitialSurroundingText.getSelectionLength() != sourceSelLength) {
+ int selStart = mInitialSurroundingText.getSelectionStart();
+ int selEnd = mInitialSurroundingText.getSelectionEnd();
+ if (selStart > selEnd) {
+ int tmp = selStart;
+ selStart = selEnd;
+ selEnd = tmp;
+ }
+ final int selLength = selEnd - selStart;
+ if (initialSelStart < 0 || initialSelEnd < 0 || selLength != sourceSelLength) {
return null;
}
- return mInitialSurroundingText.getInitialSelectedText(flags);
+
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mInitialSurroundingText.getText().subSequence(selStart, selEnd)
+ : TextUtils.substring(mInitialSurroundingText.getText(), selStart, selEnd);
}
/**
@@ -763,7 +794,79 @@ public class EditorInfo implements InputType, Parcelable {
*/
@Nullable
public CharSequence getInitialTextAfterCursor(int length, int flags) {
- return mInitialSurroundingText.getInitialTextAfterCursor(length, flags);
+ if (mInitialSurroundingText == null) {
+ return null;
+ }
+
+ int surroundingTextLength = mInitialSurroundingText.getText().length();
+ int selEnd = Math.max(mInitialSurroundingText.getSelectionStart(),
+ mInitialSurroundingText.getSelectionEnd());
+ int n = Math.min(length, surroundingTextLength - selEnd);
+ return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mInitialSurroundingText.getText().subSequence(selEnd, selEnd + n)
+ : TextUtils.substring(mInitialSurroundingText.getText(), selEnd, selEnd + n);
+ }
+
+ /**
+ * Gets the surrounding text around the current cursor, with <var>beforeLength</var> characters
+ * of text before the cursor (start of the selection), <var>afterLength</var> characters of text
+ * after the cursor (end of the selection), and all of the selected text.
+ *
+ * <p>The initial surrounding text for return could be trimmed if oversize. Fundamental trimming
+ * rules are:</p>
+ * <ul>
+ * <li>The text before the cursor is the most important information to IMEs.</li>
+ * <li>The text after the cursor is the second important information to IMEs.</li>
+ * <li>The selected text is the least important information but it shall NEVER be truncated.
+ * When it is too long, just drop it.</li>
+ * </ul>
+ *
+ * <p>For example, the subText can be viewed as TextBeforeCursor + Selection + TextAfterCursor.
+ * The result could be:</p>
+ * <ol>
+ * <li>(maybeTrimmedAtHead)TextBeforeCursor + Selection
+ * + TextAfterCursor(maybeTrimmedAtTail)</li>
+ * <li>(maybeTrimmedAtHead)TextBeforeCursor + TextAfterCursor(maybeTrimmedAtTail)</li>
+ * </ol>
+ *
+ * @param beforeLength The expected length of the text before the cursor.
+ * @param afterLength The expected length of the text after the cursor.
+ * @param flags Supplies additional options controlling how the text is returned. May be either
+ * {@code 0} or {@link InputConnection#GET_TEXT_WITH_STYLES}.
+ * @return an {@link android.view.inputmethod.SurroundingText} object describing the surrounding
+ * text and state of selection, or {@code null} if the editor or system could not support this
+ * protocol.
+ * @throws IllegalArgumentException if {@code beforeLength} or {@code afterLength} is negative.
+ */
+ @Nullable
+ public SurroundingText getInitialSurroundingText(
+ @IntRange(from = 0) int beforeLength, @IntRange(from = 0) int afterLength,
+ @InputConnection.GetTextType int flags) {
+ Preconditions.checkArgumentNonnegative(beforeLength);
+ Preconditions.checkArgumentNonnegative(afterLength);
+
+ if (mInitialSurroundingText == null) {
+ return null;
+ }
+
+ int length = mInitialSurroundingText.getText().length();
+ int selStart = mInitialSurroundingText.getSelectionStart();
+ int selEnd = mInitialSurroundingText.getSelectionEnd();
+ if (selStart > selEnd) {
+ int tmp = selStart;
+ selStart = selEnd;
+ selEnd = tmp;
+ }
+
+ int before = Math.min(beforeLength, selStart);
+ int after = Math.min(selEnd + afterLength, length);
+ int offset = selStart - before;
+ CharSequence newText = ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
+ ? mInitialSurroundingText.getText().subSequence(offset, after)
+ : TextUtils.substring(mInitialSurroundingText.getText(), offset, after);
+ int newSelEnd = Math.min(selEnd - offset, length);
+ return new SurroundingText(newText, before, newSelEnd,
+ mInitialSurroundingText.getOffset() + offset);
}
private static boolean isCutOnSurrogate(CharSequence sourceText, int cutPosition,
@@ -893,7 +996,10 @@ public class EditorInfo implements InputType, Parcelable {
dest.writeInt(fieldId);
dest.writeString(fieldName);
dest.writeBundle(extras);
- mInitialSurroundingText.writeToParcel(dest, flags);
+ dest.writeBoolean(mInitialSurroundingText != null);
+ if (mInitialSurroundingText != null) {
+ mInitialSurroundingText.writeToParcel(dest, flags);
+ }
if (hintLocales != null) {
hintLocales.writeToParcel(dest, flags);
} else {
@@ -925,9 +1031,11 @@ public class EditorInfo implements InputType, Parcelable {
res.fieldId = source.readInt();
res.fieldName = source.readString();
res.extras = source.readBundle();
- InitialSurroundingText initialSurroundingText =
- InitialSurroundingText.CREATOR.createFromParcel(source);
- res.mInitialSurroundingText = initialSurroundingText;
+ boolean hasInitialSurroundingText = source.readBoolean();
+ if (hasInitialSurroundingText) {
+ res.mInitialSurroundingText =
+ SurroundingText.CREATOR.createFromParcel(source);
+ }
LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
res.contentMimeTypes = source.readStringArray();
@@ -943,120 +1051,4 @@ public class EditorInfo implements InputType, Parcelable {
public int describeContents() {
return 0;
}
-
- static final class InitialSurroundingText implements Parcelable {
- @Nullable final CharSequence mSurroundingText;
- final int mSelectionHead;
- final int mSelectionEnd;
-
- InitialSurroundingText() {
- mSurroundingText = null;
- mSelectionHead = 0;
- mSelectionEnd = 0;
- }
-
- InitialSurroundingText(@Nullable CharSequence surroundingText, int selectionHead,
- int selectionEnd) {
- // Copy the original text (without NoCopySpan) in case the original text is updated
- // later.
- mSurroundingText = copyWithParcelableSpans(surroundingText);
- mSelectionHead = selectionHead;
- mSelectionEnd = selectionEnd;
- }
-
- @Nullable
- private CharSequence getInitialTextBeforeCursor(int n, int flags) {
- if (mSurroundingText == null) {
- return null;
- }
-
- final int length = Math.min(n, mSelectionHead);
- return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
- ? mSurroundingText.subSequence(mSelectionHead - length, mSelectionHead)
- : TextUtils.substring(mSurroundingText, mSelectionHead - length,
- mSelectionHead);
- }
-
- @Nullable
- private CharSequence getInitialSelectedText(int flags) {
- if (mSurroundingText == null) {
- return null;
- }
-
- return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
- ? mSurroundingText.subSequence(mSelectionHead, mSelectionEnd)
- : TextUtils.substring(mSurroundingText, mSelectionHead, mSelectionEnd);
- }
-
- @Nullable
- private CharSequence getInitialTextAfterCursor(int n, int flags) {
- if (mSurroundingText == null) {
- return null;
- }
-
- final int length = Math.min(n, mSurroundingText.length() - mSelectionEnd);
- return ((flags & InputConnection.GET_TEXT_WITH_STYLES) != 0)
- ? mSurroundingText.subSequence(mSelectionEnd, mSelectionEnd + length)
- : TextUtils.substring(mSurroundingText, mSelectionEnd, mSelectionEnd + length);
- }
-
- private int getSelectionLength() {
- return mSelectionEnd - mSelectionHead;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- TextUtils.writeToParcel(mSurroundingText, dest, flags);
- dest.writeInt(mSelectionHead);
- dest.writeInt(mSelectionEnd);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<InitialSurroundingText>
- CREATOR = new Parcelable.Creator<InitialSurroundingText>() {
- @Override
- public InitialSurroundingText createFromParcel(Parcel source) {
- final CharSequence initialText =
- TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
- final int selectionHead = source.readInt();
- final int selectionEnd = source.readInt();
-
- return new InitialSurroundingText(initialText, selectionHead, selectionEnd);
- }
-
- @Override
- public InitialSurroundingText[] newArray(int size) {
- return new InitialSurroundingText[size];
- }
- };
-
- /**
- * Create a copy of the given {@link CharSequence} object, with completely copy
- * {@link ParcelableSpan} instances.
- *
- * @param source the original {@link CharSequence} to be copied.
- * @return the copied {@link CharSequence}. {@code null} if {@code source} is {@code null}.
- */
- @Nullable
- private static CharSequence copyWithParcelableSpans(@Nullable CharSequence source) {
- if (source == null) {
- return null;
- }
- Parcel parcel = null;
- try {
- parcel = Parcel.obtain();
- TextUtils.writeToParcel(source, parcel, /* parcelableFlags= */ 0);
- parcel.setDataPosition(0);
- return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
- } finally {
- if (parcel != null) {
- parcel.recycle();
- }
- }
- }
- }
-}
+} \ No newline at end of file
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8c81143e4cdc..a76d46d1c00f 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1002,4 +1002,22 @@ public interface InputConnection {
*/
boolean commitContent(@NonNull InputContentInfo inputContentInfo, int flags,
@Nullable Bundle opts);
+
+ /**
+ * Called by the input method to indicate that it temporarily consumes all input for itself,
+ * or no longer does so.
+ *
+ * <p>Editors should reflect that they are temporarily not receiving input by hiding the
+ * cursor if {@code imeTemporarilyConsumesInput} is {@code true}, and resume showing the
+ * cursor if it is {@code false}.
+ *
+ * @param imeTemporarilyConsumesInput {@code true} when the IME is temporarily consuming input
+ * and the cursor should be hidden, {@code false} when input to the editor resumes and the
+ * cursor should be shown again.
+ * @return {@code true} on success, {@code false} if the input connection is no longer valid, or
+ * the protocol is not supported.
+ */
+ default boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ return false;
+ }
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index ca853485d4f3..b29149fc1fa0 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -335,4 +335,13 @@ public class InputConnectionWrapper implements InputConnection {
public boolean commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts) {
return mTarget.commitContent(inputContentInfo, flags, opts);
}
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
+ @Override
+ public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ return mTarget.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ }
}
diff --git a/core/java/android/view/inputmethod/SurroundingText.java b/core/java/android/view/inputmethod/SurroundingText.java
index 94e05a830b85..c85a18a1df79 100644
--- a/core/java/android/view/inputmethod/SurroundingText.java
+++ b/core/java/android/view/inputmethod/SurroundingText.java
@@ -18,6 +18,7 @@ package android.view.inputmethod;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -74,7 +75,7 @@ public final class SurroundingText implements Parcelable {
public SurroundingText(@NonNull final CharSequence text,
@IntRange(from = 0) int selectionStart, @IntRange(from = 0) int selectionEnd,
@IntRange(from = -1) int offset) {
- mText = text;
+ mText = copyWithParcelableSpans(text);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
mOffset = offset;
@@ -155,4 +156,29 @@ public final class SurroundingText implements Parcelable {
return new SurroundingText[size];
}
};
+
+ /**
+ * Create a copy of the given {@link CharSequence} object, with completely copy
+ * {@link ParcelableSpan} instances.
+ *
+ * @param source the original {@link CharSequence} to be copied.
+ * @return the copied {@link CharSequence}. {@code null} if {@code source} is {@code null}.
+ */
+ @Nullable
+ private static CharSequence copyWithParcelableSpans(@Nullable CharSequence source) {
+ if (source == null) {
+ return null;
+ }
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ TextUtils.writeToParcel(source, parcel, /* parcelableFlags= */ 0);
+ parcel.setDataPosition(0);
+ return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
}
diff --git a/core/java/android/webkit/TEST_MAPPING b/core/java/android/webkit/TEST_MAPPING
new file mode 100644
index 000000000000..bd25200ffc38
--- /dev/null
+++ b/core/java/android/webkit/TEST_MAPPING
@@ -0,0 +1,36 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWebkitTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsHostsideWebViewTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "GtsWebViewTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.test.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "GtsWebViewHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.test.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 4ba1ca8989b7..4a84851eb075 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -18,6 +18,7 @@ package android.widget;
import android.annotation.ColorInt;
import android.annotation.DimenRes;
+import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
@@ -63,12 +64,15 @@ import android.util.ArrayMap;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
+import android.util.TypedValue;
+import android.util.TypedValue.ComplexDimensionUnit;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.LayoutInflater.Filter;
import android.view.RemotableViewMethod;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewStub;
import android.widget.AdapterView.OnItemClickListener;
@@ -173,6 +177,48 @@ public class RemoteViews implements Parcelable, Filter {
private static final int SET_INT_TAG_TAG = 22;
/** @hide **/
+ @IntDef(prefix = "MARGIN_", value = {
+ MARGIN_LEFT,
+ MARGIN_TOP,
+ MARGIN_RIGHT,
+ MARGIN_BOTTOM,
+ MARGIN_START,
+ MARGIN_END
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MarginType {}
+ /**
+ * The value will apply to the marginLeft.
+ * @hide
+ */
+ public static final int MARGIN_LEFT = 0;
+ /**
+ * The value will apply to the marginTop.
+ * @hide
+ */
+ public static final int MARGIN_TOP = 1;
+ /**
+ * The value will apply to the marginRight.
+ * @hide
+ */
+ public static final int MARGIN_RIGHT = 2;
+ /**
+ * The value will apply to the marginBottom.
+ * @hide
+ */
+ public static final int MARGIN_BOTTOM = 3;
+ /**
+ * The value will apply to the marginStart.
+ * @hide
+ */
+ public static final int MARGIN_START = 4;
+ /**
+ * The value will apply to the marginEnd.
+ * @hide
+ */
+ public static final int MARGIN_END = 5;
+
+ /** @hide **/
@IntDef(flag = true, value = {
FLAG_REAPPLY_DISALLOWED,
FLAG_WIDGET_IS_COLLECTION_CHILD,
@@ -1730,8 +1776,16 @@ public class RemoteViews implements Parcelable, Filter {
final ViewGroup targetVg = (ViewGroup) target.mRoot;
- // Clear all children when nested views omitted
- target.mChildren = null;
+ if (mViewIdToKeep == REMOVE_ALL_VIEWS_ID) {
+ // Clear all children when there's no excepted view
+ target.mChildren = null;
+ } else {
+ // Remove just the children which don't match the excepted view
+ target.mChildren.removeIf(childTree -> childTree.mRoot.getId() != mViewIdToKeep);
+ if (target.mChildren.isEmpty()) {
+ target.mChildren = null;
+ }
+ }
return new RuntimeAction() {
@Override
public void apply(View root, ViewGroup rootParent, OnClickHandler handler)
@@ -1922,13 +1976,13 @@ public class RemoteViews implements Parcelable, Filter {
* Helper action to set text size on a TextView in any supported units.
*/
private class TextViewSizeAction extends Action {
- public TextViewSizeAction(int viewId, int units, float size) {
+ TextViewSizeAction(@IdRes int viewId, @ComplexDimensionUnit int units, float size) {
this.viewId = viewId;
this.units = units;
this.size = size;
}
- public TextViewSizeAction(Parcel parcel) {
+ TextViewSizeAction(Parcel parcel) {
viewId = parcel.readInt();
units = parcel.readInt();
size = parcel.readFloat();
@@ -2004,36 +2058,56 @@ public class RemoteViews implements Parcelable, Filter {
*/
private static class LayoutParamAction extends Action {
- /** Set marginEnd */
- public static final int LAYOUT_MARGIN_END_DIMEN = 1;
- /** Set width */
- public static final int LAYOUT_WIDTH = 2;
- public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3;
- public static final int LAYOUT_MARGIN_END = 4;
+ static final int LAYOUT_MARGIN_LEFT = MARGIN_LEFT;
+ static final int LAYOUT_MARGIN_TOP = MARGIN_TOP;
+ static final int LAYOUT_MARGIN_RIGHT = MARGIN_RIGHT;
+ static final int LAYOUT_MARGIN_BOTTOM = MARGIN_BOTTOM;
+ static final int LAYOUT_MARGIN_START = MARGIN_START;
+ static final int LAYOUT_MARGIN_END = MARGIN_END;
+ static final int LAYOUT_WIDTH = 8;
+ static final int LAYOUT_HEIGHT = 9;
final int mProperty;
+ final boolean mIsDimen;
final int mValue;
/**
* @param viewId ID of the view alter
* @param property which layout parameter to alter
* @param value new value of the layout parameter
+ * @param units the units of the given value
+ */
+ LayoutParamAction(@IdRes int viewId, int property, float value,
+ @ComplexDimensionUnit int units) {
+ this.viewId = viewId;
+ this.mProperty = property;
+ this.mIsDimen = false;
+ this.mValue = TypedValue.createComplexDimension(value, units);
+ }
+
+ /**
+ * @param viewId ID of the view alter
+ * @param property which layout parameter to alter
+ * @param dimen new dimension with the value of the layout parameter
*/
- public LayoutParamAction(int viewId, int property, int value) {
+ LayoutParamAction(@IdRes int viewId, int property, @DimenRes int dimen) {
this.viewId = viewId;
this.mProperty = property;
- this.mValue = value;
+ this.mIsDimen = true;
+ this.mValue = dimen;
}
public LayoutParamAction(Parcel parcel) {
viewId = parcel.readInt();
mProperty = parcel.readInt();
+ mIsDimen = parcel.readBoolean();
mValue = parcel.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(viewId);
dest.writeInt(mProperty);
+ dest.writeBoolean(mIsDimen);
dest.writeInt(mValue);
}
@@ -2047,26 +2121,49 @@ public class RemoteViews implements Parcelable, Filter {
if (layoutParams == null) {
return;
}
- int value = mValue;
switch (mProperty) {
- case LAYOUT_MARGIN_END_DIMEN:
- value = resolveDimenPixelOffset(target, mValue);
- // fall-through
- case LAYOUT_MARGIN_END:
- if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+ case LAYOUT_MARGIN_LEFT:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).leftMargin = getPixelOffset(target);
target.setLayoutParams(layoutParams);
}
break;
- case LAYOUT_MARGIN_BOTTOM_DIMEN:
- if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
- int resolved = resolveDimenPixelOffset(target, mValue);
- ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = resolved;
+ case LAYOUT_MARGIN_TOP:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).topMargin = getPixelOffset(target);
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_MARGIN_RIGHT:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).rightMargin = getPixelOffset(target);
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_MARGIN_BOTTOM:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).bottomMargin = getPixelOffset(target);
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_MARGIN_START:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).setMarginStart(getPixelOffset(target));
+ target.setLayoutParams(layoutParams);
+ }
+ break;
+ case LAYOUT_MARGIN_END:
+ if (layoutParams instanceof MarginLayoutParams) {
+ ((MarginLayoutParams) layoutParams).setMarginEnd(getPixelOffset(target));
target.setLayoutParams(layoutParams);
}
break;
case LAYOUT_WIDTH:
- layoutParams.width = mValue;
+ layoutParams.width = getPixelSize(target);
+ target.setLayoutParams(layoutParams);
+ break;
+ case LAYOUT_HEIGHT:
+ layoutParams.height = getPixelSize(target);
target.setLayoutParams(layoutParams);
break;
default:
@@ -2074,11 +2171,26 @@ public class RemoteViews implements Parcelable, Filter {
}
}
- private static int resolveDimenPixelOffset(View target, int value) {
- if (value == 0) {
- return 0;
+ private int getPixelOffset(View target) {
+ if (mIsDimen) {
+ if (mValue == 0) {
+ return 0;
+ }
+ return target.getResources().getDimensionPixelOffset(mValue);
+ }
+ return TypedValue.complexToDimensionPixelOffset(mValue,
+ target.getResources().getDisplayMetrics());
+ }
+
+ private int getPixelSize(View target) {
+ if (mIsDimen) {
+ if (mValue == 0) {
+ return 0;
+ }
+ return target.getResources().getDimensionPixelSize(mValue);
}
- return target.getContext().getResources().getDimensionPixelOffset(value);
+ return TypedValue.complexToDimensionPixelSize(mValue,
+ target.getResources().getDisplayMetrics());
}
@Override
@@ -2512,6 +2624,7 @@ public class RemoteViews implements Parcelable, Filter {
* @param nestedView {@link RemoteViews} that describes the child.
*/
public void addView(int viewId, RemoteViews nestedView) {
+ // Clear all children when nested views omitted
addAction(nestedView == null
? new ViewGroupActionRemove(viewId)
: new ViewGroupActionAdd(viewId, nestedView));
@@ -3044,57 +3157,94 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
- * @hide
- * Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}.
+ * Equivalent to calling {@link MarginLayoutParams#setMarginEnd}.
* Only works if the {@link View#getLayoutParams()} supports margins.
- * Hidden for now since we don't want to support this for all different layout margins yet.
*
* @param viewId The id of the view to change
- * @param endMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
+ * @param type The margin being set e.g. {@link #MARGIN_END}
+ * @param dimen a dimension resource to apply to the margin, or 0 to clear the margin.
+ * @hide
*/
- public void setViewLayoutMarginEndDimen(int viewId, @DimenRes int endMarginDimen) {
- addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END_DIMEN,
- endMarginDimen));
+ public void setViewLayoutMarginDimen(@IdRes int viewId, @MarginType int type,
+ @DimenRes int dimen) {
+ addAction(new LayoutParamAction(viewId, type, dimen));
}
/**
- * Equivalent to calling {@link android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)}.
+ * Equivalent to calling {@link MarginLayoutParams#setMarginEnd}.
* Only works if the {@link View#getLayoutParams()} supports margins.
- * Hidden for now since we don't want to support this for all different layout margins yet.
+ *
+ * <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0.
+ * Setting margins in pixels will behave poorly when the RemoteViews object is used on a
+ * display with a different density.
*
* @param viewId The id of the view to change
- * @param endMargin a value in pixels for the end margin.
+ * @param type The margin being set e.g. {@link #MARGIN_END}
+ * @param value a value for the margin the given units.
+ * @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
* @hide
*/
- public void setViewLayoutMarginEnd(int viewId, @DimenRes int endMargin) {
- addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END,
- endMargin));
+ public void setViewLayoutMargin(@IdRes int viewId, @MarginType int type, float value,
+ @ComplexDimensionUnit int units) {
+ addAction(new LayoutParamAction(viewId, type, value, units));
}
/**
- * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}.
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width} except that you may
+ * provide the value in any dimension units.
*
- * @param bottomMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
+ * <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0,
+ * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, or {@link ViewGroup.LayoutParams#MATCH_PARENT}.
+ * Setting actual sizes in pixels will behave poorly when the RemoteViews object is used on a
+ * display with a different density.
+ *
+ * @param width Width of the view in the given units
+ * @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
* @hide
*/
- public void setViewLayoutMarginBottomDimen(int viewId, @DimenRes int bottomMarginDimen) {
- addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM_DIMEN,
- bottomMarginDimen));
+ public void setViewLayoutWidth(@IdRes int viewId, float width,
+ @ComplexDimensionUnit int units) {
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, width, units));
}
/**
- * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width} with
+ * the result of {@link Resources#getDimensionPixelSize(int)}.
*
- * @param layoutWidth one of 0, MATCH_PARENT or WRAP_CONTENT. Other sizes are not allowed
- * because they behave poorly when the density changes.
+ * @param widthDimen the dimension resource for the view's width
* @hide
*/
- public void setViewLayoutWidth(int viewId, int layoutWidth) {
- if (layoutWidth != 0 && layoutWidth != ViewGroup.LayoutParams.MATCH_PARENT
- && layoutWidth != ViewGroup.LayoutParams.WRAP_CONTENT) {
- throw new IllegalArgumentException("Only supports 0, WRAP_CONTENT and MATCH_PARENT");
- }
- mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
+ public void setViewLayoutWidthDimen(@IdRes int viewId, @DimenRes int widthDimen) {
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, widthDimen));
+ }
+
+ /**
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#height} except that you may
+ * provide the value in any dimension units.
+ *
+ * <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0,
+ * {@link ViewGroup.LayoutParams#WRAP_CONTENT}, or {@link ViewGroup.LayoutParams#MATCH_PARENT}.
+ * Setting actual sizes in pixels will behave poorly when the RemoteViews object is used on a
+ * display with a different density.
+ *
+ * @param height height of the view in the given units
+ * @param units The unit type of the value e.g. {@link TypedValue#COMPLEX_UNIT_DIP}
+ * @hide
+ */
+ public void setViewLayoutHeight(@IdRes int viewId, float height,
+ @ComplexDimensionUnit int units) {
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_HEIGHT, height, units));
+ }
+
+ /**
+ * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#height} with
+ * the result of {@link Resources#getDimensionPixelSize(int)}.
+ *
+ * @param heightDimen a dimen resource to read the height from.
+ * @hide
+ */
+ public void setViewLayoutHeightDimen(@IdRes int viewId, @DimenRes int heightDimen) {
+ addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_HEIGHT, heightDimen));
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 4edfc5f309b2..1599f2bdef2e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -494,6 +494,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private TextUtils.TruncateAt mEllipsize;
+ // A flag to indicate the cursor was hidden by IME.
+ private boolean mImeTemporarilyConsumesInput;
+
+ // Whether cursor is visible without regard to {@link mImeTemporarilyConsumesInput}.
+ // {code true} is the default value.
+ private boolean mCursorVisibleFromAttr = true;
+
static class Drawables {
static final int LEFT = 0;
static final int TOP = 1;
@@ -10496,7 +10503,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Set whether the cursor is visible. The default is true. Note that this property only
- * makes sense for editable TextView.
+ * makes sense for editable TextView. If IME is temporarily consuming the input, the cursor will
+ * be always invisible, visibility will be updated as the last state when IME does not consume
+ * the input anymore.
*
* @see #isCursorVisible()
*
@@ -10504,6 +10513,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
@android.view.RemotableViewMethod
public void setCursorVisible(boolean visible) {
+ mCursorVisibleFromAttr = visible;
+ updateCursorVisibleInternal();
+ }
+
+ /**
+ * Sets the IME is temporarily consuming the input and make the cursor invisible if
+ * {@code imeTemporarilyConsumesInput} is {@code true}. Otherwise, make the cursor visible.
+ *
+ * @param imeTemporarilyConsumesInput {@code true} if IME is temporarily consuming the input
+ *
+ * @hide
+ */
+ public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ mImeTemporarilyConsumesInput = imeTemporarilyConsumesInput;
+ updateCursorVisibleInternal();
+ }
+
+ private void updateCursorVisibleInternal() {
+ boolean visible = mCursorVisibleFromAttr && !mImeTemporarilyConsumesInput;
if (visible && mEditor == null) return; // visible is the default value with no edit data
createEditorIfNeeded();
if (mEditor.mCursorVisible != visible) {
@@ -10518,7 +10546,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * @return whether or not the cursor is visible (assuming this TextView is editable)
+ * @return whether or not the cursor is visible (assuming this TextView is editable). This
+ * method may return {@code false} when the IME is temporarily consuming the input even if the
+ * {@code mEditor.mCursorVisible} attribute is {@code true} or {@code #setCursorVisible(true)}
+ * is called.
*
* @see #setCursorVisible(boolean)
*
diff --git a/core/java/android/window/ITransitionPlayer.aidl b/core/java/android/window/ITransitionPlayer.aidl
index a8a29b26a148..55d47cb7ed8b 100644
--- a/core/java/android/window/ITransitionPlayer.aidl
+++ b/core/java/android/window/ITransitionPlayer.aidl
@@ -16,6 +16,7 @@
package android.window;
+import android.app.ActivityManager;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.WindowContainerTransaction;
@@ -58,6 +59,9 @@ oneway interface ITransitionPlayer {
* @param type The {@link WindowManager#TransitionType} of the transition to start.
* @param transitionToken An identifying token for the transition that needs to be started.
* Pass this to {@link IWindowOrganizerController#startTransition}.
+ * @param triggerTask If non-null, the task containing the activity whose lifecycle change
+ * (start or finish) has caused this transition to occur.
*/
- void requestStartTransition(int type, in IBinder transitionToken);
+ void requestStartTransition(int type, in IBinder transitionToken,
+ in ActivityManager.RunningTaskInfo triggerTask);
}
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index da291cf0fd2c..d1d49b6d4722 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -26,6 +26,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Parcel;
@@ -153,7 +154,8 @@ public final class TransitionInfo implements Parcelable {
/**
* @return a surfacecontrol that can serve as a parent surfacecontrol for all the changing
* participants to animate within. This will generally be placed at the highest-z-order
- * shared ancestor of all participants.
+ * shared ancestor of all participants. While this is non-null, it's possible for the rootleash
+ * to be invalid if the transition is a no-op.
*/
@NonNull
public SurfaceControl getRootLeash() {
@@ -181,7 +183,7 @@ public final class TransitionInfo implements Parcelable {
@Nullable
public Change getChange(@NonNull WindowContainerToken token) {
for (int i = mChanges.size() - 1; i >= 0; --i) {
- if (mChanges.get(i).mContainer == token) {
+ if (token.equals(mChanges.get(i).mContainer)) {
return mChanges.get(i);
}
}
@@ -254,6 +256,7 @@ public final class TransitionInfo implements Parcelable {
private final Rect mStartAbsBounds = new Rect();
private final Rect mEndAbsBounds = new Rect();
private final Point mEndRelOffset = new Point();
+ private ActivityManager.RunningTaskInfo mTaskInfo = null;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container;
@@ -270,6 +273,7 @@ public final class TransitionInfo implements Parcelable {
mStartAbsBounds.readFromParcel(in);
mEndAbsBounds.readFromParcel(in);
mEndRelOffset.readFromParcel(in);
+ mTaskInfo = in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
}
/** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -302,6 +306,14 @@ public final class TransitionInfo implements Parcelable {
mEndRelOffset.set(left, top);
}
+ /**
+ * Sets the taskinfo of this container if this is a task. WARNING: this takes the
+ * reference, so don't modify it afterwards.
+ */
+ public void setTaskInfo(ActivityManager.RunningTaskInfo taskInfo) {
+ mTaskInfo = taskInfo;
+ }
+
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable
public WindowContainerToken getContainer() {
@@ -359,6 +371,12 @@ public final class TransitionInfo implements Parcelable {
return mLeash;
}
+ /** @return the task info or null if this isn't a task */
+ @NonNull
+ public ActivityManager.RunningTaskInfo getTaskInfo() {
+ return mTaskInfo;
+ }
+
@Override
/** @hide */
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -370,6 +388,7 @@ public final class TransitionInfo implements Parcelable {
mStartAbsBounds.writeToParcel(dest, flags);
mEndAbsBounds.writeToParcel(dest, flags);
mEndRelOffset.writeToParcel(dest, flags);
+ dest.writeTypedObject(mTaskInfo, flags);
}
@NonNull
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
index 248feb8bcbd7..e9e39db90437 100644
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ b/core/java/com/android/internal/inputmethod/CallbackUtils.java
@@ -200,4 +200,29 @@ public final class CallbackUtils {
callback.onResult(result);
} catch (RemoteException ignored) { }
}
+
+ /**
+ * A utility method using given {@link IVoidResultCallback} to callback the result.
+ *
+ * @param callback {@link IVoidResultCallback} to be called back.
+ * @param resultSupplier the supplier from which the result is provided.
+ */
+ public static void onResult(@NonNull IVoidResultCallback callback,
+ @NonNull Supplier<Void> resultSupplier) {
+ Throwable exception = null;
+
+ try {
+ resultSupplier.get();
+ } catch (Throwable throwable) {
+ exception = throwable;
+ }
+
+ try {
+ if (exception != null) {
+ callback.onError(ThrowableHolder.of(exception));
+ return;
+ }
+ callback.onResult();
+ } catch (RemoteException ignored) { }
+ }
}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
index 1913fcdc9ba9..b82ba8132889 100644
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ b/core/java/com/android/internal/inputmethod/Completable.java
@@ -286,6 +286,42 @@ public final class Completable {
}
/**
+ * Completable object of {@link java.lang.Void}.
+ */
+ public static final class Void extends ValueBase {
+ /**
+ * Notify when this completable object callback.
+ */
+ @AnyThread
+ @Override
+ protected void onComplete() {
+ synchronized (mStateLock) {
+ switch (mState) {
+ case CompletionState.NOT_COMPLETED:
+ mState = CompletionState.COMPLETED_WITH_VALUE;
+ break;
+ default:
+ throw new UnsupportedOperationException(
+ "onComplete() is not allowed on state=" + stateToString(mState));
+ }
+ }
+ super.onComplete();
+ }
+
+ /**
+ * @throws RuntimeException when called while {@link #onError} happened.
+ * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
+ * {@code false}.
+ */
+ @AnyThread
+ public void getValue() {
+ synchronized (mStateLock) {
+ enforceGetValueLocked();
+ }
+ }
+ }
+
+ /**
* Base class of completable object types.
*
* @param <T> type associated with this completable object.
@@ -396,6 +432,13 @@ public final class Completable {
}
/**
+ * @return an instance of {@link Completable.Void}.
+ */
+ public static Completable.Void createVoid() {
+ return new Completable.Void();
+ }
+
+ /**
* Completable object of {@link java.lang.Boolean}.
*/
public static final class Boolean extends Values<java.lang.Boolean> { }
@@ -465,6 +508,17 @@ public final class Completable {
}
/**
+ * Await the result by the {@link Completable.Void}.
+ *
+ * Check the result once {@link ValueBase#onComplete()}
+ */
+ @AnyThread
+ public static void getResult(@NonNull Completable.Void value) {
+ value.await();
+ value.getValue();
+ }
+
+ /**
* Await the result by the {@link Completable.Int}, and log it if there is no result after
* given timeout.
*
diff --git a/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl b/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
new file mode 100644
index 000000000000..0b25a2b886c9
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import com.android.internal.inputmethod.ThrowableHolder;
+
+oneway interface IVoidResultCallback {
+ void onResult();
+ void onError(in ThrowableHolder exception);
+} \ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
index 6ce851b59ccd..2a48c1f60aa9 100644
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
@@ -352,4 +352,39 @@ public final class ResultCallbacks {
}
};
}
+
+ /**
+ * Creates {@link IVoidResultCallback.Stub} that is to set {@link Completable.Void} when
+ * receiving the result.
+ *
+ * @param value {@link Completable.Void} to be set when receiving the result.
+ * @return {@link IVoidResultCallback.Stub} that can be passed as a binder IPC parameter.
+ */
+ @AnyThread
+ public static IVoidResultCallback.Stub of(@NonNull Completable.Void value) {
+ final AtomicReference<WeakReference<Completable.Void>> atomicRef =
+ new AtomicReference<>(new WeakReference<>(value));
+
+ return new IVoidResultCallback.Stub() {
+ @BinderThread
+ @Override
+ public void onResult() {
+ final Completable.Void value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onComplete();
+ }
+
+ @BinderThread
+ @Override
+ public void onError(ThrowableHolder throwableHolder) {
+ final Completable.Void value = unwrap(atomicRef);
+ if (value == null) {
+ return;
+ }
+ value.onError(throwableHolder);
+ }
+ };
+ }
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 771a72c98a7a..1e2ce288974c 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -463,7 +463,7 @@ public class InteractionJankMonitor {
}
public String getName() {
- return "Cuj<" + getNameOfCuj(mCujType) + ">";
+ return "J<" + getNameOfCuj(mCujType) + ">";
}
}
}
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index 2dd51b4459e7..f7fad2c5bbaa 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -143,10 +143,6 @@ public abstract class KernelCpuUidTimeReader<T> {
*/
public void removeUid(int uid) {
mLastTimes.delete(uid);
-
- if (mBpfTimesAvailable) {
- mBpfReader.removeUidsInRange(uid, uid);
- }
}
/**
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index 254c2997fa65..1e9801f5ef30 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -91,18 +91,6 @@ public class LatencyTracker {
*/
public static final int ACTION_START_RECENTS_ANIMATION = 8;
- private static final String[] NAMES = new String[]{
- "expand panel",
- "toggle recents",
- "fingerprint wake-and-unlock",
- "check credential",
- "check credential unlocked",
- "turn on screen",
- "rotate the screen",
- "face wake-and-unlock",
- "start recents-animation",
- };
-
private static final int[] STATSD_ACTION = new int[]{
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_EXPAND_PANEL,
FrameworkStatsLog.UIACTION_LATENCY_REPORTED__ACTION__ACTION_TOGGLE_RECENTS,
@@ -185,6 +173,10 @@ public class LatencyTracker {
}
}
+ private String getTraceNameOfAcion(int action) {
+ return "L<" + getNameOfAction(action) + ">";
+ }
+
public static boolean isEnabled(Context ctx) {
return getInstance(ctx).isEnabled();
}
@@ -202,7 +194,7 @@ public class LatencyTracker {
if (!isEnabled()) {
return;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, NAMES[action], 0);
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_APP, getTraceNameOfAcion(action), 0);
mStartRtc.put(action, SystemClock.elapsedRealtime());
}
@@ -221,7 +213,7 @@ public class LatencyTracker {
return;
}
mStartRtc.delete(action);
- Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, getTraceNameOfAcion(action), 0);
logAction(action, (int) (endRtc - startRtc));
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 3a7e66ce76f0..e7b7bf4a5b52 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -79,6 +79,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_CLOSE_CONNECTION = 150;
private static final int DO_COMMIT_CONTENT = 160;
private static final int DO_GET_SURROUNDING_TEXT = 41;
+ private static final int DO_SET_IME_TEMPORARILY_CONSUMES_INPUT = 170;
@GuardedBy("mLock")
@@ -266,6 +267,16 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
dispatchMessage(mH.obtainMessage(DO_COMMIT_CONTENT, flags, 0 /* unused */, args));
}
+ /**
+ * Dispatches the request for setting ime temporarily consumes input.
+ *
+ * <p>See {@link InputConnection#setImeTemporarilyConsumesInput(boolean)}.
+ */
+ public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ dispatchMessage(obtainMessageB(DO_SET_IME_TEMPORARILY_CONSUMES_INPUT,
+ imeTemporarilyConsumesInput));
+ }
+
void dispatchMessage(Message msg) {
// If we are calling this from the main thread, then we can call
// right through. Otherwise, we need to send the message to the
@@ -811,6 +822,22 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
return;
}
+ case DO_SET_IME_TEMPORARILY_CONSUMES_INPUT: {
+ Trace.traceBegin(Trace.TRACE_TAG_INPUT,
+ "InputConnection#setImeTemporarilyConsumesInput");
+ try {
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG,
+ "setImeTemporarilyConsumesInput on inactive InputConnection");
+ return;
+ }
+ ic.setImeTemporarilyConsumesInput(msg.arg1 == 1);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_INPUT);
+ }
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -837,4 +864,8 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
args.arg2 = arg2;
return mH.obtainMessage(what, 0, 0, args);
}
+
+ Message obtainMessageB(int what, boolean arg1) {
+ return mH.obtainMessage(what, arg1 ? 1 : 0, 0);
+ }
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 53cbf961fff4..586404c53f18 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -85,4 +85,6 @@ import com.android.internal.inputmethod.ISurroundingTextResultCallback;
void getSurroundingText(int beforeLength, int afterLength, int flags,
ISurroundingTextResultCallback callback);
+
+ void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index af9c0124078a..84c92ca83f36 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -524,6 +524,19 @@ public class InputConnectionWrapper implements InputConnection {
value, TAG, "commitContent()", mCancellationGroup, MAX_WAIT_TIME_MILLIS) != 0;
}
+ /**
+ * See {@link InputConnection#setImeTemporarilyConsumesInput(boolean)}.
+ */
+ @AnyThread
+ public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ try {
+ mIInputContext.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
@AnyThread
private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
return (mMissingMethods & methodFlag) == methodFlag;
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 767ad42efbf3..4ccf9ce91f27 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -245,6 +245,15 @@ public class EditableInputConnection extends BaseInputConnection
}
@Override
+ public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ if (mTextView == null) {
+ return super.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ }
+ mTextView.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ return true;
+ }
+
+ @Override
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
CharSequence editableText = mTextView.getText();
diff --git a/core/tests/coretests/src/android/util/TypedValueTest.kt b/core/tests/coretests/src/android/util/TypedValueTest.kt
new file mode 100644
index 000000000000..7a05d970de33
--- /dev/null
+++ b/core/tests/coretests/src/android/util/TypedValueTest.kt
@@ -0,0 +1,155 @@
+/*
+ * 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.util
+
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import kotlin.math.abs
+import kotlin.math.min
+import kotlin.math.roundToInt
+
+@RunWith(AndroidJUnit4::class)
+class TypedValueTest {
+ @LargeTest
+ @Test
+ fun testFloatToComplex() {
+ fun assertRoundTripEquals(value: Float, expectedRadix: Int? = null) {
+ val complex = TypedValue.floatToComplex(value)
+ // Ensure values are accurate within .5% of the original value and within .5
+ val delta = min(abs(value) / 512f, .5f)
+ assertEquals(value, TypedValue.complexToFloat(complex), delta)
+ // If expectedRadix is provided, validate it
+ if (expectedRadix != null) {
+ val actualRadix = ((complex shr TypedValue.COMPLEX_RADIX_SHIFT)
+ and TypedValue.COMPLEX_RADIX_MASK)
+ assertEquals("Incorrect radix for $value:", expectedRadix, actualRadix)
+ }
+ }
+
+ assertRoundTripEquals(0f, TypedValue.COMPLEX_RADIX_23p0)
+
+ assertRoundTripEquals(0.5f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(0.05f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(0.005f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(0.0005f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(0.00005f, TypedValue.COMPLEX_RADIX_0p23)
+
+ assertRoundTripEquals(1.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(10.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(100.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(255.5f, TypedValue.COMPLEX_RADIX_8p15) // 2^8 - .5
+
+ assertRoundTripEquals(256.5f, TypedValue.COMPLEX_RADIX_16p7) // 2^8 + .5
+ assertRoundTripEquals(1000.5f, TypedValue.COMPLEX_RADIX_16p7)
+ assertRoundTripEquals(10000.5f, TypedValue.COMPLEX_RADIX_16p7)
+ assertRoundTripEquals(65535.5f, TypedValue.COMPLEX_RADIX_16p7) // 2^16 - .5
+
+ assertRoundTripEquals(65536.5f, TypedValue.COMPLEX_RADIX_23p0) // 2^16 + .5
+ assertRoundTripEquals(100000.5f, TypedValue.COMPLEX_RADIX_23p0)
+ assertRoundTripEquals(1000000.5f, TypedValue.COMPLEX_RADIX_23p0)
+ assertRoundTripEquals(8388607.2f, TypedValue.COMPLEX_RADIX_23p0) // 2^23 -.8
+
+ assertRoundTripEquals(-0.5f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(-0.05f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(-0.005f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(-0.0005f, TypedValue.COMPLEX_RADIX_0p23)
+ assertRoundTripEquals(-0.00005f, TypedValue.COMPLEX_RADIX_0p23)
+
+ assertRoundTripEquals(-1.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(-10.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(-100.5f, TypedValue.COMPLEX_RADIX_8p15)
+ assertRoundTripEquals(-255.5f, TypedValue.COMPLEX_RADIX_8p15) // -2^8 + .5
+
+ // NOTE: -256.5f fits in COMPLEX_RADIX_8p15 but is stored with COMPLEX_RADIX_16p7 for
+ // simplicity of the algorithm. However, it's better not to enforce that with a test.
+ assertRoundTripEquals(-257.5f, TypedValue.COMPLEX_RADIX_16p7) // -2^8 - 1.5
+ assertRoundTripEquals(-1000.5f, TypedValue.COMPLEX_RADIX_16p7)
+ assertRoundTripEquals(-10000.5f, TypedValue.COMPLEX_RADIX_16p7)
+ assertRoundTripEquals(-65535.5f, TypedValue.COMPLEX_RADIX_16p7) // -2^16 + .5
+
+ // NOTE: -65536.5f fits in COMPLEX_RADIX_16p7 but is stored with COMPLEX_RADIX_23p0 for
+ // simplicity of the algorithm. However, it's better not to enforce that with a test.
+ assertRoundTripEquals(-65537.5f, TypedValue.COMPLEX_RADIX_23p0) // -2^16 - 1.5
+ assertRoundTripEquals(-100000.5f, TypedValue.COMPLEX_RADIX_23p0)
+ assertRoundTripEquals(-1000000.5f, TypedValue.COMPLEX_RADIX_23p0)
+ assertRoundTripEquals(-8388607.5f, TypedValue.COMPLEX_RADIX_23p0) // 2^23 -.5
+
+ // Test for every integer value in the range...
+ for (i: Int in -(1 shl 23) until (1 shl 23)) {
+ // ... that true integers are stored as the precise integer
+ assertRoundTripEquals(i.toFloat(), TypedValue.COMPLEX_RADIX_23p0)
+ // ... that values round up when just below an integer
+ assertRoundTripEquals(i - .1f)
+ // ... that values round down when just above an integer
+ assertRoundTripEquals(i + .1f)
+ }
+ }
+
+ @SmallTest
+ @Test(expected = IllegalArgumentException::class)
+ fun testFloatToComplex_failsIfValueTooLarge() {
+ TypedValue.floatToComplex(8388607.5f) // 2^23 - .5
+ }
+
+ @SmallTest
+ @Test(expected = IllegalArgumentException::class)
+ fun testFloatToComplex_failsIfValueTooSmall() {
+ TypedValue.floatToComplex(8388608.5f) // -2^23 - .5
+ }
+
+ @LargeTest
+ @Test
+ fun testIntToComplex() {
+ // Validates every single valid value
+ for (value: Int in -(1 shl 23) until (1 shl 23)) {
+ assertEquals(value.toFloat(), TypedValue.complexToFloat(TypedValue.intToComplex(value)))
+ }
+ }
+
+ @SmallTest
+ @Test(expected = IllegalArgumentException::class)
+ fun testIntToComplex_failsIfValueTooLarge() {
+ TypedValue.intToComplex(0x800000)
+ }
+
+ @SmallTest
+ @Test(expected = IllegalArgumentException::class)
+ fun testIntToComplex_failsIfValueTooSmall() {
+ TypedValue.intToComplex(-0x800001)
+ }
+
+ @SmallTest
+ @Test
+ fun testCreateComplexDimension_appliesUnits() {
+ val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+ metrics.density = 3.25f
+
+ val height = 52 * metrics.density
+ val widthFloat = height * 16 / 9
+ val widthDimen = TypedValue.createComplexDimension(
+ widthFloat / metrics.density,
+ TypedValue.COMPLEX_UNIT_DIP
+ )
+ val widthPx = TypedValue.complexToDimensionPixelSize(widthDimen, metrics)
+ assertEquals(widthFloat.roundToInt(), widthPx)
+ }
+} \ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
index 92fb52837c36..c636912ee98d 100644
--- a/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/EditorInfoTest.java
@@ -109,11 +109,15 @@ public class EditorInfoTest {
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
final int expectedTextBeforeCursorLength = 0;
final int expectedTextAfterCursorLength = testText.length();
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(testText, editorInfo.initialSelStart,
+ editorInfo.initialSelEnd, 0);
+
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
+ expectedTextAfterCursorLength, expectedSurroundingText);
}
@Test
@@ -125,11 +129,14 @@ public class EditorInfoTest {
editorInfo.initialSelEnd = testText.length();
final int expectedTextBeforeCursorLength = testText.length();
final int expectedTextAfterCursorLength = 0;
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(testText, editorInfo.initialSelStart,
+ editorInfo.initialSelEnd, 0);
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
+ expectedTextAfterCursorLength, expectedSurroundingText);
}
@Test
@@ -141,11 +148,14 @@ public class EditorInfoTest {
editorInfo.initialSelEnd = editorInfo.initialSelStart + selectionLength;
final int expectedTextBeforeCursorLength = editorInfo.initialSelStart;
final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(testText, editorInfo.initialSelStart,
+ editorInfo.initialSelEnd, 0);
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
+ expectedTextAfterCursorLength, expectedSurroundingText);
}
@Test
@@ -158,11 +168,14 @@ public class EditorInfoTest {
final int expectedTextBeforeCursorLength = testText.length() / 2;
final int expectedTextAfterCursorLength = testText.length() - testText.length() / 2
- selectionLength;
-
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(testText,
+ editorInfo.initialSelEnd,
+ editorInfo.initialSelStart , 0);
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
+ expectedTextAfterCursorLength, expectedSurroundingText);
}
@Test
@@ -174,9 +187,10 @@ public class EditorInfoTest {
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo,
- /* expectBeforeCursorLength= */null,
- /* expectSelectionLength= */null,
- /* expectAfterCursorLength= */null);
+ /* expectBeforeCursorLength= */ null,
+ /* expectSelectionLength= */ null,
+ /* expectAfterCursorLength= */ null,
+ /* expectSurroundingText= */ null);
}
@Test
@@ -190,11 +204,23 @@ public class EditorInfoTest {
(int) (0.8 * (EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH - selectionLength)));
final int expectedTextAfterCursorLength = EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH
- expectedTextBeforeCursorLength - selectionLength;
+ final int offset = editorInfo.initialSelStart - expectedTextBeforeCursorLength;
+ final CharSequence beforeCursor = testText.subSequence(
+ offset, offset + expectedTextBeforeCursorLength);
+ final CharSequence afterCursor = testText.subSequence(editorInfo.initialSelEnd,
+ editorInfo.initialSelEnd + expectedTextAfterCursorLength);
+ final CharSequence selectedText = testText.subSequence(editorInfo.initialSelStart,
+ editorInfo.initialSelEnd);
+
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(TextUtils.concat(beforeCursor, selectedText, afterCursor),
+ expectedTextBeforeCursorLength,
+ expectedTextBeforeCursorLength + selectionLength, offset);
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength, selectionLength,
- expectedTextAfterCursorLength);
+ expectedTextAfterCursorLength, expectedSurroundingText);
}
@Test
@@ -207,11 +233,22 @@ public class EditorInfoTest {
final int expectedTextBeforeCursorLength = Math.min(editorInfo.initialSelStart,
(int) (0.8 * EditorInfo.MEMORY_EFFICIENT_TEXT_LENGTH));
final int expectedTextAfterCursorLength = testText.length() - editorInfo.initialSelEnd;
+ final CharSequence before = testText.subSequence(
+ editorInfo.initialSelStart - expectedTextBeforeCursorLength,
+ expectedTextBeforeCursorLength);
+ final CharSequence after = testText.subSequence(editorInfo.initialSelEnd,
+ editorInfo.initialSelEnd + expectedTextAfterCursorLength);
+ final SurroundingText expectedSurroundingText =
+ new SurroundingText(TextUtils.concat(before, after),
+ expectedTextBeforeCursorLength,
+ expectedTextBeforeCursorLength,
+ editorInfo.initialSelStart - expectedTextBeforeCursorLength);
editorInfo.setInitialSurroundingText(testText);
assertExpectedTextLength(editorInfo, expectedTextBeforeCursorLength,
- /* expectSelectionLength= */null, expectedTextAfterCursorLength);
+ /* expectSelectionLength= */null, expectedTextAfterCursorLength,
+ expectedSurroundingText);
}
@Test
@@ -269,6 +306,19 @@ public class EditorInfoTest {
InputConnection.GET_TEXT_WITH_STYLES),
targetEditorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES)));
+
+ final SurroundingText sourceSurroundingText = sourceEditorInfo.getInitialSurroundingText(
+ LONG_EXP_TEXT_LENGTH, LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES);
+ final SurroundingText targetSurroundingText = targetEditorInfo.getInitialSurroundingText(
+ LONG_EXP_TEXT_LENGTH, LONG_EXP_TEXT_LENGTH, InputConnection.GET_TEXT_WITH_STYLES);
+
+ assertTrue(TextUtils.equals(sourceSurroundingText.getText(),
+ targetSurroundingText.getText()));
+ assertEquals(sourceSurroundingText.getSelectionStart(),
+ targetSurroundingText.getSelectionStart());
+ assertEquals(sourceSurroundingText.getSelectionEnd(),
+ targetSurroundingText.getSelectionEnd());
+ assertEquals(sourceSurroundingText.getOffset(), targetSurroundingText.getOffset());
}
@Test
@@ -338,7 +388,8 @@ public class EditorInfoTest {
private static void assertExpectedTextLength(EditorInfo editorInfo,
@Nullable Integer expectBeforeCursorLength, @Nullable Integer expectSelectionLength,
- @Nullable Integer expectAfterCursorLength) {
+ @Nullable Integer expectAfterCursorLength,
+ @Nullable SurroundingText expectSurroundingText) {
final CharSequence textBeforeCursor =
editorInfo.getInitialTextBeforeCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES);
@@ -347,6 +398,10 @@ public class EditorInfoTest {
final CharSequence textAfterCursor =
editorInfo.getInitialTextAfterCursor(LONG_EXP_TEXT_LENGTH,
InputConnection.GET_TEXT_WITH_STYLES);
+ final SurroundingText surroundingText = editorInfo.getInitialSurroundingText(
+ LONG_EXP_TEXT_LENGTH,
+ LONG_EXP_TEXT_LENGTH,
+ InputConnection.GET_TEXT_WITH_STYLES);
if (expectBeforeCursorLength == null) {
assertNull(textBeforeCursor);
@@ -365,6 +420,18 @@ public class EditorInfoTest {
} else {
assertEquals(expectAfterCursorLength.intValue(), textAfterCursor.length());
}
+
+ if (expectSurroundingText == null) {
+ assertNull(surroundingText);
+ } else {
+ assertTrue(TextUtils.equals(
+ expectSurroundingText.getText(), surroundingText.getText()));
+ assertEquals(expectSurroundingText.getSelectionStart(),
+ surroundingText.getSelectionStart());
+ assertEquals(expectSurroundingText.getSelectionEnd(),
+ surroundingText.getSelectionEnd());
+ assertEquals(expectSurroundingText.getOffset(), surroundingText.getOffset());
+ }
}
private static CharSequence createTestText(int surroundingLength) {
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 66fdfff990f8..a4284a04310e 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -276,6 +276,34 @@ public class TextViewTest {
0, mTextView.getImeOptions() & EditorInfo.IME_FLAG_NO_FULLSCREEN);
}
+ @Test
+ @UiThreadTest
+ public void setSetImeTemporarilyConsumesInput_recoveryToVisible() {
+ mTextView = new TextView(mActivity);
+ mTextView.setCursorVisible(true);
+ assertTrue(mTextView.isCursorVisible());
+
+ mTextView.setImeTemporarilyConsumesInput(true);
+ assertFalse(mTextView.isCursorVisible());
+
+ mTextView.setImeTemporarilyConsumesInput(false);
+ assertTrue(mTextView.isCursorVisible());
+ }
+
+ @Test
+ @UiThreadTest
+ public void setSetImeTemporarilyConsumesInput_recoveryToInvisible() {
+ mTextView = new TextView(mActivity);
+ mTextView.setCursorVisible(false);
+ assertFalse(mTextView.isCursorVisible());
+
+ mTextView.setImeTemporarilyConsumesInput(true);
+ assertFalse(mTextView.isCursorVisible());
+
+ mTextView.setImeTemporarilyConsumesInput(false);
+ assertFalse(mTextView.isCursorVisible());
+ }
+
private String createLongText() {
int size = 600 * 1000;
final StringBuilder builder = new StringBuilder(size);
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 9f46ceb61332..49888fd5f977 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -204,6 +204,26 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
}
/**
+ * Draws a ripple
+ *
+ * @param cx
+ * @param cy
+ * @param radius
+ * @param paint
+ * @param progress
+ * @param shader
+ *
+ * @hide
+ */
+ public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
+ CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
+ CanvasProperty<Float> progress, RuntimeShader shader) {
+ nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
+ radius.getNativeContainer(), paint.getNativeContainer(),
+ progress.getNativeContainer(), shader.getNativeShaderFactory());
+ }
+
+ /**
* Draws a round rect
*
* @param left
@@ -260,6 +280,9 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
private static native void nDrawCircle(long renderer, long propCx,
long propCy, long propRadius, long propPaint);
@CriticalNative
+ private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
+ long propPaint, long propProgress, long runtimeEffect);
+ @CriticalNative
private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
long propRight, long propBottom, long propRx, long propRy, long propPaint);
@CriticalNative
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index fb0983a83f9d..7f2e503ac8fd 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -115,6 +115,10 @@ public class RuntimeShader extends Shader {
nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
}
+ public long getNativeShaderFactory() {
+ return mNativeInstanceRuntimeShaderFactory;
+ }
+
private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
deleted file mode 100644
index 9157f63ce1b3..000000000000
--- a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<!-- Layout for {@link com.android.wm.shell.pip.tv.PipControlsView}. -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <com.android.wm.shell.pip.tv.PipControlButtonView
- android:id="@+id/full_button"
- android:layout_width="@dimen/picture_in_picture_button_width"
- android:layout_height="wrap_content"
- android:src="@drawable/pip_ic_fullscreen_white"
- android:text="@string/pip_fullscreen" />
-
- <com.android.wm.shell.pip.tv.PipControlButtonView
- android:id="@+id/close_button"
- android:layout_width="@dimen/picture_in_picture_button_width"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
- android:src="@drawable/pip_ic_close_white"
- android:text="@string/pip_close" />
-</merge>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index 0d684e8b0ab5..49e2379589a4 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -14,19 +14,39 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tv_pip_menu"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:paddingTop="350dp"
- android:background="#CC000000"
- android:gravity="top|center_horizontal"
- android:clipChildren="false">
-
- <com.android.wm.shell.pip.tv.PipControlsView
- android:id="@+id/pip_controls"
+<!-- Layout for TvPipMenuView -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tv_pip_menu"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#CC000000">
+
+ <LinearLayout
+ android:id="@+id/tv_pip_menu_action_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:alpha="0" />
-</LinearLayout>
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="350dp"
+ android:orientation="horizontal"
+ android:alpha="0">
+
+ <com.android.wm.shell.pip.tv.TvPipMenuActionButton
+ android:id="@+id/tv_pip_menu_fullscreen_button"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:src="@drawable/pip_ic_fullscreen_white"
+ android:text="@string/pip_fullscreen" />
+
+ <com.android.wm.shell.pip.tv.TvPipMenuActionButton
+ android:id="@+id/tv_pip_menu_close_button"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin"
+ android:src="@drawable/pip_ic_close_white"
+ android:text="@string/pip_close" />
+
+ <!-- More TvPipMenuActionButtons may be added here at runtime. -->
+
+ </LinearLayout>
+
+</FrameLayout>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml
index 727ac3412a25..5925008e0d08 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu_action_button.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- Layout for {@link com.android.wm.shell.pip.tv.PipControlButtonView}. -->
+<!-- Layout for TvPipMenuActionButton -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:id="@+id/button"
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu_additional_action_button.xml
index 452f2cd5ccb6..bf4eb2691ff0 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu_additional_action_button.xml
@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.wm.shell.pip.tv.PipControlButtonView
+<com.android.wm.shell.pip.tv.TvPipMenuActionButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
index 63d31182a748..8817f8aaec7c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/FullscreenTaskListener.java
@@ -55,19 +55,16 @@ public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
taskInfo.taskId);
mLeashByTaskId.put(taskInfo.taskId, leash);
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
final Point positionInParent = taskInfo.positionInParent;
mSyncQueue.runInSync(t -> {
// Reset several properties back to fullscreen (PiP, for example, leaves all these
// properties in a bad state).
t.setWindowCrop(leash, null);
t.setPosition(leash, positionInParent.x, positionInParent.y);
- // TODO(shell-transitions): Eventually set everything in transition so there's no
- // SF Transaction here.
- if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
- t.setAlpha(leash, 1f);
- t.setMatrix(leash, 1, 0, 0, 1);
- t.show(leash);
- }
+ t.setAlpha(leash, 1f);
+ t.setMatrix(leash, 1, 0, 0, 1);
+ t.show(leash);
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
index 54863d23643a..5213f6c80989 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/Transitions.java
@@ -16,6 +16,7 @@
package com.android.wm.shell;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -25,15 +26,17 @@ import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPI
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.ArrayMap;
-import android.util.Slog;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.window.ITransitionPlayer;
import android.window.TransitionInfo;
+import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import androidx.annotation.BinderThread;
@@ -59,8 +62,16 @@ public class Transitions {
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
+ /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
+ private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
+
+ private static final class ActiveTransition {
+ ArrayList<Animator> mAnimations = null;
+ TransitionHandler mFirstHandler = null;
+ }
+
/** Keeps track of currently tracked transitions and all the animations associated with each */
- private final ArrayMap<IBinder, ArrayList<Animator>> mActiveTransitions = new ArrayMap<>();
+ private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
@@ -75,6 +86,22 @@ public class Transitions {
taskOrganizer.registerTransitionPlayer(mPlayerImpl);
}
+ /**
+ * Adds a handler candidate.
+ * @see TransitionHandler
+ */
+ public void addHandler(@NonNull TransitionHandler handler) {
+ mHandlers.add(handler);
+ }
+
+ public ShellExecutor getMainExecutor() {
+ return mMainExecutor;
+ }
+
+ public ShellExecutor getAnimExecutor() {
+ return mAnimExecutor;
+ }
+
// TODO(shell-transitions): real animations
private void startExampleAnimation(@NonNull IBinder transition, @NonNull SurfaceControl leash,
boolean show) {
@@ -93,7 +120,7 @@ public class Transitions {
transaction.apply();
mTransactionPool.release(transaction);
mMainExecutor.execute(() -> {
- mActiveTransitions.get(transition).remove(va);
+ mActiveTransitions.get(transition).mAnimations.remove(va);
onFinish(transition);
});
};
@@ -114,30 +141,23 @@ public class Transitions {
@Override
public void onAnimationRepeat(Animator animation) { }
});
- mActiveTransitions.get(transition).add(va);
+ mActiveTransitions.get(transition).mAnimations.add(va);
mAnimExecutor.execute(va::start);
}
- private static boolean isOpeningType(@WindowManager.TransitionType int type) {
+ /** @return true if the transition was triggered by opening something vs closing something */
+ public static boolean isOpeningType(@WindowManager.TransitionType int type) {
return type == TRANSIT_OPEN
|| type == TRANSIT_TO_FRONT
|| type == WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
}
- private void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
+ /**
+ * Reparents all participants into a shared parent and orders them based on: the global transit
+ * type, their transit mode, and their destination z-order.
+ */
+ private static void setupStartState(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t) {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
- transitionToken, info);
- // start task
- if (!mActiveTransitions.containsKey(transitionToken)) {
- Slog.e(TAG, "Got transitionReady for non-active transition " + transitionToken
- + " expecting one of " + mActiveTransitions.keySet());
- }
- if (mActiveTransitions.get(transitionToken) != null) {
- throw new IllegalStateException("Got a duplicate onTransitionReady call for "
- + transitionToken);
- }
- mActiveTransitions.put(transitionToken, new ArrayList<>());
boolean isOpening = isOpeningType(info.getType());
if (info.getRootLeash().isValid()) {
t.show(info.getRootLeash());
@@ -148,24 +168,26 @@ public class Transitions {
final SurfaceControl leash = change.getLeash();
final int mode = info.getChanges().get(i).getMode();
- // Don't animate anything with an animating parent
+ // Don't move anything with an animating parent
if (change.getParent() != null) {
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
+ if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
t.show(leash);
t.setMatrix(leash, 1, 0, 0, 1);
+ t.setAlpha(leash, 1.f);
+ t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
}
continue;
}
t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getEndAbsBounds().left - info.getRootOffset().x,
- change.getEndAbsBounds().top - info.getRootOffset().y);
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
t.show(leash);
t.setMatrix(leash, 1, 0, 0, 1);
if (isOpening) {
- // put on top and fade in
+ // put on top with 0 alpha
t.setLayer(leash, info.getChanges().size() - i);
if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
// This received a transferred starting window, so make it immediately
@@ -173,47 +195,155 @@ public class Transitions {
t.setAlpha(leash, 1.f);
} else {
t.setAlpha(leash, 0.f);
- startExampleAnimation(transitionToken, leash, true /* show */);
}
} else {
- // put on bottom and leave it visible without fade
+ // put on bottom and leave it visible
t.setLayer(leash, -i);
t.setAlpha(leash, 1.f);
}
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
if (isOpening) {
- // put on bottom and leave visible without fade
+ // put on bottom and leave visible
t.setLayer(leash, -i);
} else {
- // put on top and fade out
+ // put on top
t.setLayer(leash, info.getChanges().size() - i);
- startExampleAnimation(transitionToken, leash, false /* show */);
}
- } else {
+ } else { // CHANGE
t.setLayer(leash, info.getChanges().size() - i);
}
}
+ }
+
+ private void onTransitionReady(@NonNull IBinder transitionToken, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "onTransitionReady %s: %s",
+ transitionToken, info);
+ final ActiveTransition active = mActiveTransitions.get(transitionToken);
+ if (active == null) {
+ throw new IllegalStateException("Got transitionReady for non-active transition "
+ + transitionToken + ". expecting one of " + mActiveTransitions.keySet());
+ }
+ if (active.mAnimations != null) {
+ throw new IllegalStateException("Got a duplicate onTransitionReady call for "
+ + transitionToken);
+ }
+ if (!info.getRootLeash().isValid()) {
+ // Invalid root-leash implies that the transition is empty/no-op, so just do
+ // housekeeping and return.
+ t.apply();
+ onFinish(transitionToken);
+ return;
+ }
+
+ setupStartState(info, t);
+
+ final Runnable finishRunnable = () -> onFinish(transitionToken);
+ // If a handler chose to uniquely run this animation, try delegating to it.
+ if (active.mFirstHandler != null && active.mFirstHandler.startAnimation(
+ transitionToken, info, t, finishRunnable)) {
+ return;
+ }
+ // Otherwise give every other handler a chance (in order)
+ for (int i = mHandlers.size() - 1; i >= 0; --i) {
+ if (mHandlers.get(i) == active.mFirstHandler) continue;
+ if (mHandlers.get(i).startAnimation(transitionToken, info, t, finishRunnable)) {
+ return;
+ }
+ }
+
+ // No handler chose to perform this animation, so fall-back to the
+ // default animation handling.
+ final boolean isOpening = isOpeningType(info.getType());
+ active.mAnimations = new ArrayList<>(); // Play fade animations
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+
+ // Don't animate anything with an animating parent
+ if (change.getParent() != null) continue;
+
+ final int mode = info.getChanges().get(i).getMode();
+ if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
+ if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
+ // This received a transferred starting window, so don't animate
+ continue;
+ }
+ // fade in
+ startExampleAnimation(transitionToken, change.getLeash(), true /* show */);
+ } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
+ // fade out
+ startExampleAnimation(transitionToken, change.getLeash(), false /* show */);
+ }
+ }
t.apply();
onFinish(transitionToken);
}
private void onFinish(IBinder transition) {
- if (!mActiveTransitions.get(transition).isEmpty()) return;
+ final ActiveTransition active = mActiveTransitions.get(transition);
+ if (active.mAnimations != null && !active.mAnimations.isEmpty()) return;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"Transition animations finished, notifying core %s", transition);
mActiveTransitions.remove(transition);
mOrganizer.finishTransition(transition, null, null);
}
- private void requestStartTransition(int type, @NonNull IBinder transitionToken) {
+ private void requestStartTransition(int type, @NonNull IBinder transitionToken,
+ @Nullable ActivityManager.RunningTaskInfo triggerTask) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition requested: type=%d %s",
type, transitionToken);
if (mActiveTransitions.containsKey(transitionToken)) {
throw new RuntimeException("Transition already started " + transitionToken);
}
- IBinder transition = mOrganizer.startTransition(type, transitionToken, null /* wct */);
- mActiveTransitions.put(transition, null);
+ final ActiveTransition active = new ActiveTransition();
+ WindowContainerTransaction wct = null;
+ for (int i = mHandlers.size() - 1; i >= 0; --i) {
+ wct = mHandlers.get(i).handleRequest(type, transitionToken, triggerTask);
+ if (wct != null) {
+ active.mFirstHandler = mHandlers.get(i);
+ break;
+ }
+ }
+ IBinder transition = mOrganizer.startTransition(type, transitionToken, wct);
+ mActiveTransitions.put(transition, active);
+ }
+
+ /** Start a new transition directly. */
+ public IBinder startTransition(@WindowManager.TransitionType int type,
+ @NonNull WindowContainerTransaction wct, @Nullable TransitionHandler handler) {
+ final ActiveTransition active = new ActiveTransition();
+ active.mFirstHandler = handler;
+ IBinder transition = mOrganizer.startTransition(type, null /* token */, wct);
+ mActiveTransitions.put(transition, active);
+ return transition;
+ }
+
+ /**
+ * Interface for something which can handle a subset of transitions.
+ */
+ public interface TransitionHandler {
+ /**
+ * Starts a transition animation. This is always called if handleRequest returned non-null
+ * for a particular transition. Otherwise, it is only called if no other handler before
+ * it handled the transition.
+ *
+ * @return true if transition was handled, false if not (falls-back to default).
+ */
+ boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull Runnable finishCallback);
+
+ /**
+ * Potentially handles a startTransition request.
+ * @param type The transition type
+ * @param triggerTask The task which triggered this transition request.
+ * @return WCT to apply with transition-start or null if this handler isn't handling
+ * the request.
+ */
+ @Nullable
+ WindowContainerTransaction handleRequest(@WindowManager.TransitionType int type,
+ @NonNull IBinder transition,
+ @Nullable ActivityManager.RunningTaskInfo triggerTask);
}
@BinderThread
@@ -227,9 +357,10 @@ public class Transitions {
}
@Override
- public void requestStartTransition(int i, IBinder iBinder) throws RemoteException {
+ public void requestStartTransition(int i, IBinder iBinder,
+ ActivityManager.RunningTaskInfo runningTaskInfo) throws RemoteException {
mMainExecutor.execute(() -> {
- Transitions.this.requestStartTransition(i, iBinder);
+ Transitions.this.requestStartTransition(i, iBinder, runningTaskInfo);
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 7f3389599a51..86da2b502870 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -471,13 +471,12 @@ public class BubbleExpandedView extends LinearLayout {
mIsOverflow = overflow;
Intent target = new Intent(mContext, BubbleOverflowActivity.class);
+ target.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
Bundle extras = new Bundle();
extras.putBinder(EXTRA_BUBBLE_CONTROLLER, ObjectWrapper.wrap(mController));
target.putExtras(extras);
- // TODO(b/175352055) Please replace FLAG_MUTABLE_UNAUDITED below
- // with either FLAG_IMMUTABLE (recommended) or FLAG_MUTABLE.
mPendingIntent = PendingIntent.getActivity(mContext, 0 /* requestCode */,
- target, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ target, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mSettingsIcon.setVisibility(GONE);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
index 6b79a3661bc0..789bd1a90731 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenController.java
@@ -44,6 +44,7 @@ import android.window.WindowContainerTransaction;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
@@ -113,7 +114,7 @@ public class LegacySplitScreenController implements LegacySplitScreen,
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController imeController, Handler handler, TransactionPool transactionPool,
ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue,
- TaskStackListenerImpl taskStackListener) {
+ TaskStackListenerImpl taskStackListener, Transitions transitions) {
mContext = context;
mDisplayController = displayController;
mSystemWindows = systemWindows;
@@ -123,7 +124,8 @@ public class LegacySplitScreenController implements LegacySplitScreen,
mTransactionPool = transactionPool;
mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
mTaskOrganizer = shellTaskOrganizer;
- mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, syncQueue);
+ mSplits = new LegacySplitScreenTaskListener(this, shellTaskOrganizer, transitions,
+ syncQueue);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler,
shellTaskOrganizer);
mRotationController =
@@ -553,8 +555,36 @@ public class LegacySplitScreenController implements LegacySplitScreen,
mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
}
+ void prepareEnterSplitTransition(WindowContainerTransaction outWct) {
+ // Set resizable directly here because buildEnterSplit already resizes home stack.
+ mHomeStackResizable = mWindowManagerProxy.buildEnterSplit(outWct, mSplits, mSplitLayout);
+ }
+
+ void finishEnterSplitTransition(boolean minimized) {
+ update(mDisplayController.getDisplayContext(
+ mContext.getDisplayId()).getResources().getConfiguration());
+ if (minimized) {
+ ensureMinimizedSplit();
+ } else {
+ ensureNormalSplit();
+ }
+ }
+
void startDismissSplit(boolean toPrimaryTask) {
+ startDismissSplit(toPrimaryTask, false /* snapped */);
+ }
+
+ void startDismissSplit(boolean toPrimaryTask, boolean snapped) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ mSplits.getSplitTransitions().dismissSplit(
+ mSplits, mSplitLayout, !toPrimaryTask, snapped);
+ } else {
mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, !toPrimaryTask);
+ onDismissSplit();
+ }
+ }
+
+ void onDismissSplit() {
updateVisibility(false /* visible */);
mMinimized = false;
// Resets divider bar position to undefined, so new divider bar will apply default position
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
index 02c82dee8ca4..8c624cdb1063 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitScreenTaskListener.java
@@ -32,6 +32,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.window.TaskOrganizer;
import androidx.annotation.NonNull;
@@ -63,11 +64,17 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
final SurfaceSession mSurfaceSession = new SurfaceSession();
+ private final SplitScreenTransitions mSplitTransitions;
+
LegacySplitScreenTaskListener(LegacySplitScreenController splitScreenController,
ShellTaskOrganizer shellTaskOrganizer,
+ Transitions transitions,
SyncTransactionQueue syncQueue) {
mSplitScreenController = splitScreenController;
mTaskOrganizer = shellTaskOrganizer;
+ mSplitTransitions = new SplitScreenTransitions(splitScreenController.mTransactionPool,
+ transitions, mSplitScreenController, this);
+ transitions.addHandler(mSplitTransitions);
mSyncQueue = syncQueue;
}
@@ -98,6 +105,14 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
mSplitScreenController.mTransactionPool.release(t);
}
+ TaskOrganizer getTaskOrganizer() {
+ return mTaskOrganizer;
+ }
+
+ SplitScreenTransitions getSplitTransitions() {
+ return mSplitTransitions;
+ }
+
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (this) {
@@ -195,10 +210,12 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
mLeashByTaskId.put(taskInfo.taskId, leash);
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
}
private void handleChildTaskChanged(RunningTaskInfo taskInfo) {
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
}
@@ -241,14 +258,15 @@ class LegacySplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
} else if (info.token.asBinder() == mSecondary.token.asBinder()) {
mSecondary = info;
}
+ if (DEBUG) {
+ Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
+ }
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
final boolean primaryIsEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
&& mSplitScreenController.isHomeStackResizable());
- if (DEBUG) {
- Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
- }
if (primaryIsEmpty == primaryWasEmpty && secondaryWasEmpty == secondaryIsEmpty
&& secondaryImpliedMinimize == secondaryImpliesMinimize) {
// No relevant changes
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
new file mode 100644
index 000000000000..93520c0b59de
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/SplitScreenTransitions.java
@@ -0,0 +1,342 @@
+/*
+ * 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.wm.shell.legacysplitscreen;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.WindowConfiguration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+import android.window.TransitionInfo;
+import android.window.WindowContainerTransaction;
+
+import com.android.wm.shell.Transitions;
+import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+import java.util.ArrayList;
+
+/** Plays transition animations for split-screen */
+public class SplitScreenTransitions implements Transitions.TransitionHandler {
+ private static final String TAG = "SplitScreenTransitions";
+
+ public static final int TRANSIT_SPLIT_DISMISS_SNAP = TRANSIT_FIRST_CUSTOM + 10;
+
+ private final TransactionPool mTransactionPool;
+ private final Transitions mTransitions;
+ private final LegacySplitScreenController mSplitScreen;
+ private final LegacySplitScreenTaskListener mListener;
+
+ private IBinder mPendingDismiss = null;
+ private boolean mDismissFromSnap = false;
+ private IBinder mPendingEnter = null;
+ private IBinder mAnimatingTransition = null;
+
+ /** Keeps track of currently running animations */
+ private final ArrayList<Animator> mAnimations = new ArrayList<>();
+
+ private Runnable mFinishCallback = null;
+ private SurfaceControl.Transaction mFinishTransaction;
+
+ SplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
+ @NonNull LegacySplitScreenController splitScreen,
+ @NonNull LegacySplitScreenTaskListener listener) {
+ mTransactionPool = pool;
+ mTransitions = transitions;
+ mSplitScreen = splitScreen;
+ mListener = listener;
+ }
+
+ @Override
+ public WindowContainerTransaction handleRequest(@WindowManager.TransitionType int type,
+ @NonNull IBinder transition, @Nullable ActivityManager.RunningTaskInfo triggerTask) {
+ WindowContainerTransaction out = null;
+ if (mSplitScreen.isDividerVisible()) {
+ // try to handle everything while in split-screen
+ out = new WindowContainerTransaction();
+ if (triggerTask != null) {
+ final boolean shouldDismiss =
+ // if we close the primary-docked task, then leave split-screen since there
+ // is nothing behind it.
+ ((type == TRANSIT_CLOSE || type == TRANSIT_TO_BACK)
+ && triggerTask.parentTaskId == mListener.mPrimary.taskId)
+ // if a non-resizable is launched, we also need to leave split-screen.
+ || ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
+ && !triggerTask.isResizeable);
+ // In both cases, dismiss the primary
+ if (shouldDismiss) {
+ WindowManagerProxy.buildDismissSplit(out, mListener,
+ mSplitScreen.getSplitLayout(), true /* dismiss */);
+ if (type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT) {
+ out.reorder(triggerTask.token, true /* onTop */);
+ }
+ mPendingDismiss = transition;
+ }
+ }
+ } else if (triggerTask != null) {
+ // Not in split mode, so look for an open with a trigger task.
+ if ((type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT)
+ && triggerTask.configuration.windowConfiguration.getWindowingMode()
+ == WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ out = new WindowContainerTransaction();
+ mSplitScreen.prepareEnterSplitTransition(out);
+ mPendingEnter = transition;
+ }
+ }
+ return out;
+ }
+
+ // TODO(shell-transitions): real animations
+ private void startExampleAnimation(@NonNull SurfaceControl leash, boolean show) {
+ final float end = show ? 1.f : 0.f;
+ final float start = 1.f - end;
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ final ValueAnimator va = ValueAnimator.ofFloat(start, end);
+ va.setDuration(500);
+ va.addUpdateListener(animation -> {
+ float fraction = animation.getAnimatedFraction();
+ transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
+ transaction.apply();
+ });
+ final Runnable finisher = () -> {
+ transaction.setAlpha(leash, end);
+ transaction.apply();
+ mTransactionPool.release(transaction);
+ mTransitions.getMainExecutor().execute(() -> {
+ mAnimations.remove(va);
+ onFinish();
+ });
+ };
+ va.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) { }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finisher.run();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ finisher.run();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) { }
+ });
+ mAnimations.add(va);
+ mTransitions.getAnimExecutor().execute(va::start);
+ }
+
+ // TODO(shell-transitions): real animations
+ private void startExampleResizeAnimation(@NonNull SurfaceControl leash,
+ @NonNull Rect startBounds, @NonNull Rect endBounds) {
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ final ValueAnimator va = ValueAnimator.ofFloat(0.f, 1.f);
+ va.setDuration(500);
+ va.addUpdateListener(animation -> {
+ float fraction = animation.getAnimatedFraction();
+ transaction.setWindowCrop(leash,
+ (int) (startBounds.width() * (1.f - fraction) + endBounds.width() * fraction),
+ (int) (startBounds.height() * (1.f - fraction)
+ + endBounds.height() * fraction));
+ transaction.setPosition(leash,
+ startBounds.left * (1.f - fraction) + endBounds.left * fraction,
+ startBounds.top * (1.f - fraction) + endBounds.top * fraction);
+ transaction.apply();
+ });
+ final Runnable finisher = () -> {
+ transaction.setWindowCrop(leash, 0, 0);
+ transaction.setPosition(leash, endBounds.left, endBounds.top);
+ transaction.apply();
+ mTransactionPool.release(transaction);
+ mTransitions.getMainExecutor().execute(() -> {
+ mAnimations.remove(va);
+ onFinish();
+ });
+ };
+ va.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ finisher.run();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ finisher.run();
+ }
+ });
+ mAnimations.add(va);
+ mTransitions.getAnimExecutor().execute(va::start);
+ }
+
+ @Override
+ public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
+ if (transition != mPendingDismiss && transition != mPendingEnter) {
+ // If we're not in split-mode, just abort
+ if (!mSplitScreen.isDividerVisible()) return false;
+ // Check to see if HOME is involved
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() == null
+ || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) continue;
+ if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
+ mSplitScreen.ensureMinimizedSplit();
+ } else if (change.getMode() == TRANSIT_CLOSE
+ || change.getMode() == TRANSIT_TO_BACK) {
+ mSplitScreen.ensureNormalSplit();
+ }
+ }
+ // Use normal animations.
+ return false;
+ }
+
+ mFinishCallback = finishCallback;
+ mFinishTransaction = mTransactionPool.acquire();
+ mAnimatingTransition = transition;
+
+ // Play fade animations
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final SurfaceControl leash = change.getLeash();
+ final int mode = info.getChanges().get(i).getMode();
+
+ if (mode == TRANSIT_CHANGE) {
+ if (change.getParent() != null) {
+ // This is probably reparented, so we want the parent to be immediately visible
+ final TransitionInfo.Change parentChange = info.getChange(change.getParent());
+ t.show(parentChange.getLeash());
+ t.setAlpha(parentChange.getLeash(), 1.f);
+ // and then animate this layer outside the parent (since, for example, this is
+ // the home task animating from fullscreen to part-screen).
+ t.reparent(leash, info.getRootLeash());
+ t.setLayer(leash, info.getChanges().size() - i);
+ // build the finish reparent/reposition
+ mFinishTransaction.reparent(leash, parentChange.getLeash());
+ mFinishTransaction.setPosition(leash,
+ change.getEndRelOffset().x, change.getEndRelOffset().y);
+ }
+ // TODO(shell-transitions): screenshot here
+ final Rect startBounds = new Rect(change.getStartAbsBounds());
+ final boolean isHome = change.getTaskInfo() != null
+ && change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME;
+ if (mPendingDismiss == transition && mDismissFromSnap && !isHome) {
+ // Home is special since it doesn't move during fling. Everything else, though,
+ // when dismissing from snap, the top/left is at 0,0.
+ startBounds.offsetTo(0, 0);
+ }
+ final Rect endBounds = new Rect(change.getEndAbsBounds());
+ startBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
+ endBounds.offset(-info.getRootOffset().x, -info.getRootOffset().y);
+ startExampleResizeAnimation(leash, startBounds, endBounds);
+ }
+ if (change.getParent() != null) {
+ continue;
+ }
+
+ if (transition == mPendingEnter
+ && mListener.mPrimary.token.equals(change.getContainer())
+ || mListener.mSecondary.token.equals(change.getContainer())) {
+ t.setWindowCrop(leash, change.getStartAbsBounds().width(),
+ change.getStartAbsBounds().height());
+ if (mListener.mPrimary.token.equals(change.getContainer())) {
+ // Move layer to top since we want it above the oversized home task during
+ // animation even though home task is on top in hierarchy.
+ t.setLayer(leash, info.getChanges().size() + 1);
+ }
+ }
+ boolean isOpening = Transitions.isOpeningType(info.getType());
+ if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
+ // fade in
+ startExampleAnimation(leash, true /* show */);
+ } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
+ // fade out
+ if (transition == mPendingDismiss && mDismissFromSnap) {
+ // Dismissing via snap-to-top/bottom means that the dismissed task is already
+ // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
+ // and don't animate it so it doesn't pop-in when reparented.
+ t.setAlpha(leash, 0.f);
+ } else {
+ startExampleAnimation(leash, false /* show */);
+ }
+ }
+ }
+ if (transition == mPendingEnter) {
+ // If entering, check if we should enter into minimized or normal split
+ boolean homeIsVisible = false;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getTaskInfo() == null
+ || change.getTaskInfo().getActivityType() != ACTIVITY_TYPE_HOME) {
+ continue;
+ }
+ homeIsVisible = change.getMode() == TRANSIT_OPEN
+ || change.getMode() == TRANSIT_TO_FRONT
+ || change.getMode() == TRANSIT_CHANGE;
+ break;
+ }
+ mSplitScreen.finishEnterSplitTransition(homeIsVisible);
+ }
+ t.apply();
+ onFinish();
+ return true;
+ }
+
+ @ExternalThread
+ void dismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
+ boolean dismissOrMaximize, boolean snapped) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ WindowManagerProxy.buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
+ mTransitions.getMainExecutor().execute(() -> {
+ mDismissFromSnap = snapped;
+ mPendingDismiss = mTransitions.startTransition(TRANSIT_SPLIT_DISMISS_SNAP, wct, this);
+ });
+ }
+
+ private void onFinish() {
+ if (!mAnimations.isEmpty()) return;
+ mFinishTransaction.apply();
+ mTransactionPool.release(mFinishTransaction);
+ mFinishTransaction = null;
+ mFinishCallback.run();
+ mFinishCallback = null;
+ if (mAnimatingTransition == mPendingEnter) {
+ mPendingEnter = null;
+ }
+ if (mAnimatingTransition == mPendingDismiss) {
+ mSplitScreen.onDismissSplit();
+ mPendingDismiss = null;
+ }
+ mDismissFromSnap = false;
+ mAnimatingTransition = null;
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
index 68da35d9c4b1..90a8de02deb8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/WindowManagerProxy.java
@@ -39,6 +39,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import com.android.internal.annotations.GuardedBy;
+import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.SyncTransactionQueue;
import java.util.ArrayList;
@@ -90,7 +91,11 @@ class WindowManagerProxy {
void dismissOrMaximizeDocked(final LegacySplitScreenTaskListener tiles,
LegacySplitDisplayLayout layout, final boolean dismissOrMaximize) {
- mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ tiles.mSplitScreenController.startDismissSplit(!dismissOrMaximize, true /* snapped */);
+ } else {
+ mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
+ }
}
public void setResizing(final boolean resizing) {
@@ -181,6 +186,18 @@ class WindowManagerProxy {
return isHomeResizable;
}
+ /** @see #buildEnterSplit */
+ boolean applyEnterSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout) {
+ // Set launchtile first so that any stack created after
+ // getAllRootTaskInfos and before reparent (even if unlikely) are placed
+ // correctly.
+ mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ final boolean isHomeResizable = buildEnterSplit(wct, tiles, layout);
+ applySyncTransaction(wct);
+ return isHomeResizable;
+ }
+
/**
* Finishes entering split-screen by reparenting all FULLSCREEN tasks into the secondary split.
* This assumes there is already something in the primary split since that is usually what
@@ -189,14 +206,10 @@ class WindowManagerProxy {
*
* @return whether the home stack is resizable
*/
- boolean applyEnterSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout) {
- // Set launchtile first so that any stack created after
- // getAllRootTaskInfos and before reparent (even if unlikely) are placed
- // correctly.
- mTaskOrganizer.setLaunchRoot(DEFAULT_DISPLAY, tiles.mSecondary.token);
+ boolean buildEnterSplit(WindowContainerTransaction outWct, LegacySplitScreenTaskListener tiles,
+ LegacySplitDisplayLayout layout) {
List<ActivityManager.RunningTaskInfo> rootTasks =
mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, null /* activityTypes */);
- WindowContainerTransaction wct = new WindowContainerTransaction();
if (rootTasks.isEmpty()) {
return false;
}
@@ -215,48 +228,60 @@ class WindowManagerProxy {
// Since this iterates from bottom to top, update topHomeTask for every fullscreen task
// so it will be left with the status of the top one.
topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
- wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
+ outWct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
}
// Move the secondary split-forward.
- wct.reorder(tiles.mSecondary.token, true /* onTop */);
- boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
- if (topHomeTask != null) {
+ outWct.reorder(tiles.mSecondary.token, true /* onTop */);
+ boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */,
+ outWct);
+ if (topHomeTask != null && !Transitions.ENABLE_SHELL_TRANSITIONS) {
// Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
// is enabled, this temporarily syncs the home surface position with offset until
// sync transaction finishes.
- wct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
+ outWct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
}
- applySyncTransaction(wct);
return isHomeResizable;
}
- boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
+ static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
final int atype = ti.getActivityType();
return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
}
+ /** @see #buildDismissSplit */
+ void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
+ boolean dismissOrMaximize) {
+ // Set launch root first so that any task created after getChildContainers and
+ // before reparent (pretty unlikely) are put into fullscreen.
+ mTaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
+ // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
+ // plus specific APIs to clean this up.
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ buildDismissSplit(wct, tiles, layout, dismissOrMaximize);
+ applySyncTransaction(wct);
+ }
+
/**
* Reparents all tile members back to their display and resets home task override bounds.
* @param dismissOrMaximize When {@code true} this resolves the split by closing the primary
* split (thus resulting in the top of the secondary split becoming
* fullscreen. {@code false} resolves the other way.
*/
- void applyDismissSplit(LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
+ static void buildDismissSplit(WindowContainerTransaction outWct,
+ LegacySplitScreenTaskListener tiles, LegacySplitDisplayLayout layout,
boolean dismissOrMaximize) {
- // Set launch root first so that any task created after getChildContainers and
- // before reparent (pretty unlikely) are put into fullscreen.
- mTaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
// TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
// plus specific APIs to clean this up.
+ final TaskOrganizer taskOrg = tiles.getTaskOrganizer();
List<ActivityManager.RunningTaskInfo> primaryChildren =
- mTaskOrganizer.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
+ taskOrg.getChildTasks(tiles.mPrimary.token, null /* activityTypes */);
List<ActivityManager.RunningTaskInfo> secondaryChildren =
- mTaskOrganizer.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
+ taskOrg.getChildTasks(tiles.mSecondary.token, null /* activityTypes */);
// In some cases (eg. non-resizable is launched), system-server will leave split-screen.
// as a result, the above will not capture any tasks; yet, we need to clean-up the
// home task bounds.
List<ActivityManager.RunningTaskInfo> freeHomeAndRecents =
- mTaskOrganizer.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS);
+ taskOrg.getRootTasks(DEFAULT_DISPLAY, HOME_AND_RECENTS);
// Filter out the root split tasks
freeHomeAndRecents.removeIf(p -> p.token.equals(tiles.mSecondary.token)
|| p.token.equals(tiles.mPrimary.token));
@@ -265,11 +290,10 @@ class WindowManagerProxy {
&& freeHomeAndRecents.isEmpty()) {
return;
}
- WindowContainerTransaction wct = new WindowContainerTransaction();
if (dismissOrMaximize) {
// Dismissing, so move all primary split tasks first
for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ outWct.reparent(primaryChildren.get(i).token, null /* parent */,
true /* onTop */);
}
boolean homeOnTop = false;
@@ -277,16 +301,16 @@ class WindowManagerProxy {
// order within the secondary split.
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
- wct.reparent(ti.token, null /* parent */, true /* onTop */);
+ outWct.reparent(ti.token, null /* parent */, true /* onTop */);
if (isHomeOrRecentTask(ti)) {
- wct.setBounds(ti.token, null);
- wct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
+ outWct.setBounds(ti.token, null);
+ outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
if (i == 0) {
homeOnTop = true;
}
}
}
- if (homeOnTop) {
+ if (homeOnTop && !Transitions.ENABLE_SHELL_TRANSITIONS) {
// Translate/update-crop of secondary out-of-band with sync transaction -- instead
// play this in sync with new home-app frame because until BALST is enabled this
// shows up on screen before the syncTransaction returns.
@@ -304,7 +328,7 @@ class WindowManagerProxy {
layout.mDisplayLayout.height());
crop.offset(-posX, -posY);
sft.setWindowCrop(tiles.mSecondarySurface, crop);
- wct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
+ outWct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
}
} else {
// Maximize, so move non-home secondary split first
@@ -312,7 +336,7 @@ class WindowManagerProxy {
if (isHomeOrRecentTask(secondaryChildren.get(i))) {
continue;
}
- wct.reparent(secondaryChildren.get(i).token, null /* parent */,
+ outWct.reparent(secondaryChildren.get(i).token, null /* parent */,
true /* onTop */);
}
// Find and place home tasks in-between. This simulates the fact that there was
@@ -320,24 +344,23 @@ class WindowManagerProxy {
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
final ActivityManager.RunningTaskInfo ti = secondaryChildren.get(i);
if (isHomeOrRecentTask(ti)) {
- wct.reparent(ti.token, null /* parent */, true /* onTop */);
+ outWct.reparent(ti.token, null /* parent */, true /* onTop */);
// reset bounds and mode too
- wct.setBounds(ti.token, null);
- wct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
+ outWct.setBounds(ti.token, null);
+ outWct.setWindowingMode(ti.token, WINDOWING_MODE_UNDEFINED);
}
}
for (int i = primaryChildren.size() - 1; i >= 0; --i) {
- wct.reparent(primaryChildren.get(i).token, null /* parent */,
+ outWct.reparent(primaryChildren.get(i).token, null /* parent */,
true /* onTop */);
}
}
for (int i = freeHomeAndRecents.size() - 1; i >= 0; --i) {
- wct.setBounds(freeHomeAndRecents.get(i).token, null);
- wct.setWindowingMode(freeHomeAndRecents.get(i).token, WINDOWING_MODE_UNDEFINED);
+ outWct.setBounds(freeHomeAndRecents.get(i).token, null);
+ outWct.setWindowingMode(freeHomeAndRecents.get(i).token, WINDOWING_MODE_UNDEFINED);
}
// Reset focusable to true
- wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- applySyncTransaction(wct);
+ outWct.setFocusable(tiles.mPrimary.token, true /* focusable */);
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
index 0955056900f1..ffa6c9921d97 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java
@@ -60,7 +60,8 @@ import java.util.Objects;
/**
* Manages the picture-in-picture (PIP) UI and states.
*/
-public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback {
+public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback,
+ TvPipMenuController.Delegate {
private static final String TAG = "TvPipController";
static final boolean DEBUG = false;
@@ -198,7 +199,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mPipBoundsAlgorithm = pipBoundsAlgorithm;
mPipMediaController = pipMediaController;
mTvPipMenuController = tvPipMenuController;
- mTvPipMenuController.attachPipController(this);
+ mTvPipMenuController.setDelegate(this);
// Ensure that we have the display info in case we get calls to update the bounds
// before the listener calls back
final DisplayInfo displayInfo = new DisplayInfo();
@@ -289,6 +290,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
/**
* Closes PIP (PIPed activity and PIP system UI).
*/
+ @Override
public void closePip() {
if (DEBUG) Log.d(TAG, "closePip(), current state=" + getStateDescription());
@@ -318,9 +320,15 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
mHandler.removeCallbacks(mClosePipRunnable);
}
+ @Override
+ public void movePipToNormalPosition() {
+ resizePinnedStack(PipController.STATE_PIP);
+ }
+
/**
* Moves the PIPed activity to the fullscreen and closes PIP system UI.
*/
+ @Override
public void movePipToFullscreen() {
if (DEBUG) Log.d(TAG, "movePipToFullscreen(), current state=" + getStateDescription());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java
deleted file mode 100644
index 95d9b77c513e..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java
+++ /dev/null
@@ -1,61 +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.wm.shell.pip.tv;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.widget.LinearLayout;
-
-import com.android.wm.shell.R;
-
-
-/**
- * A view containing PIP controls including fullscreen, close, and media controls.
- */
-public class PipControlsView extends LinearLayout {
-
- public PipControlsView(Context context) {
- this(context, null);
- }
-
- public PipControlsView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- layoutInflater.inflate(R.layout.tv_pip_controls, this);
- setOrientation(LinearLayout.HORIZONTAL);
- setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
- }
-
- PipControlButtonView getFullscreenButton() {
- return findViewById(R.id.full_button);
- }
-
- PipControlButtonView getCloseButton() {
- return findViewById(R.id.close_button);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java
deleted file mode 100644
index 5265e7705ed9..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java
+++ /dev/null
@@ -1,158 +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.wm.shell.pip.tv;
-
-import android.app.PendingIntent;
-import android.app.RemoteAction;
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import com.android.wm.shell.R;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-/**
- * Controller for {@link PipControlsView}.
- */
-public class PipControlsViewController {
- private static final String TAG = PipControlsViewController.class.getSimpleName();
-
- private static final float DISABLED_ACTION_ALPHA = 0.54f;
-
- private final PipController mPipController;
-
- private final Context mContext;
- private final Handler mUiThreadHandler;
- private final PipControlsView mView;
- private final List<PipControlButtonView> mAdditionalButtons = new ArrayList<>();
-
- private final List<RemoteAction> mCustomActions = new ArrayList<>();
- private final List<RemoteAction> mMediaActions = new ArrayList<>();
-
- public PipControlsViewController(PipControlsView view, PipController pipController) {
- mContext = view.getContext();
- mUiThreadHandler = new Handler(Looper.getMainLooper());
- mPipController = pipController;
- mView = view;
-
- mView.getFullscreenButton().setOnClickListener(v -> mPipController.movePipToFullscreen());
- mView.getCloseButton().setOnClickListener(v -> mPipController.closePip());
-
- mPipController.getPipMediaController().addActionListener(this::onMediaActionsChanged);
- }
-
- PipControlsView getView() {
- return mView;
- }
-
- /**
- * Updates the set of activity-defined actions.
- */
- void setCustomActions(List<? extends RemoteAction> actions) {
- if (mCustomActions.isEmpty() && actions.isEmpty()) {
- // Nothing changed - return early.
- return;
- }
- mCustomActions.clear();
- mCustomActions.addAll(actions);
- updateAdditionalActions();
- }
-
- private void onMediaActionsChanged(List<RemoteAction> actions) {
- if (mMediaActions.isEmpty() && actions.isEmpty()) {
- // Nothing changed - return early.
- return;
- }
- mMediaActions.clear();
- mMediaActions.addAll(actions);
-
- // Update the view only if there are no custom actions (media actions are only shown when
- // there no custom actions).
- if (mCustomActions.isEmpty()) {
- updateAdditionalActions();
- }
- }
-
- private void updateAdditionalActions() {
- final List<RemoteAction> actionsToDisplay;
- if (!mCustomActions.isEmpty()) {
- // If there are custom actions: show them.
- actionsToDisplay = mCustomActions;
- } else if (!mMediaActions.isEmpty()) {
- // If there are no custom actions, but there media actions: show them.
- actionsToDisplay = mMediaActions;
- } else {
- // If there no custom actions and no media actions: clean up all the additional buttons.
- actionsToDisplay = Collections.emptyList();
- }
-
- // Make sure we exactly as many additional buttons as we have actions to display.
- final int actionsNumber = actionsToDisplay.size();
- int buttonsNumber = mAdditionalButtons.size();
- if (actionsNumber > buttonsNumber) {
- final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
- // Add buttons until we have enough to display all of the actions.
- while (actionsNumber > buttonsNumber) {
- final PipControlButtonView button = (PipControlButtonView) layoutInflater.inflate(
- R.layout.tv_pip_custom_control, mView, false);
- mView.addView(button);
- mAdditionalButtons.add(button);
-
- buttonsNumber++;
- }
- } else if (actionsNumber < buttonsNumber) {
- // Hide buttons until we as many as the actions.
- while (actionsNumber < buttonsNumber) {
- final View button = mAdditionalButtons.get(buttonsNumber - 1);
- button.setVisibility(View.GONE);
- button.setOnClickListener(null);
-
- buttonsNumber--;
- }
- }
-
- // "Assign" actions to the buttons.
- for (int index = 0; index < actionsNumber; index++) {
- final RemoteAction action = actionsToDisplay.get(index);
- final PipControlButtonView button = mAdditionalButtons.get(index);
- button.setVisibility(View.VISIBLE); // Ensure the button is visible.
- button.setText(action.getContentDescription());
- button.setEnabled(action.isEnabled());
- button.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
- button.setOnClickListener(v -> {
- try {
- action.getActionIntent().send();
- } catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "Failed to send action", e);
- }
- });
-
- action.getIcon().loadDrawableAsync(mContext, drawable -> {
- drawable.setTint(Color.WHITE);
- button.setImageDrawable(drawable);
- }, mUiThreadHandler);
- }
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
deleted file mode 100644
index 83cb7ce8065b..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuView.java
+++ /dev/null
@@ -1,126 +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.wm.shell.pip.tv;
-
-import static android.view.KeyEvent.ACTION_UP;
-import static android.view.KeyEvent.KEYCODE_BACK;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.annotation.Nullable;
-import android.app.RemoteAction;
-import android.content.Context;
-import android.content.pm.ParceledListSlice;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.SurfaceControl;
-import android.view.ViewRootImpl;
-import android.view.WindowManagerGlobal;
-import android.widget.FrameLayout;
-
-import com.android.wm.shell.R;
-
-import java.util.Collections;
-
-/**
- * The Menu View that shows controls of the PiP. Always fullscreen.
- */
-public class PipMenuView extends FrameLayout {
- private static final String TAG = "PipMenuView";
- private static final boolean DEBUG = PipController.DEBUG;
-
- private final Animator mFadeInAnimation;
- private final Animator mFadeOutAnimation;
- private final PipControlsViewController mPipControlsViewController;
- @Nullable
- private OnBackPressListener mOnBackPressListener;
-
- public PipMenuView(Context context, PipController pipController) {
- super(context, null, 0);
- inflate(context, R.layout.tv_pip_menu, this);
-
- mPipControlsViewController = new PipControlsViewController(
- findViewById(R.id.pip_controls), pipController);
- mFadeInAnimation = AnimatorInflater.loadAnimator(
- mContext, R.anim.tv_pip_menu_fade_in_animation);
- mFadeInAnimation.setTarget(mPipControlsViewController.getView());
- mFadeOutAnimation = AnimatorInflater.loadAnimator(
- mContext, R.anim.tv_pip_menu_fade_out_animation);
- mFadeOutAnimation.setTarget(mPipControlsViewController.getView());
- }
-
- @Nullable
- SurfaceControl getWindowSurfaceControl() {
- final ViewRootImpl root = getViewRootImpl();
- if (root == null) {
- return null;
- }
- final SurfaceControl out = root.getSurfaceControl();
- if (out != null && out.isValid()) {
- return out;
- }
- return null;
- }
-
- void showMenu() {
- mFadeInAnimation.start();
- setAlpha(1.0f);
- grantWindowFocus(true);
- }
-
- void hideMenu() {
- mFadeOutAnimation.start();
- setAlpha(0.0f);
- grantWindowFocus(false);
- }
-
- private void grantWindowFocus(boolean grantFocus) {
- try {
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- getViewRootImpl().getInputToken(), grantFocus);
- } catch (Exception e) {
- Log.e(TAG, "Unable to update focus as menu disappears", e);
- }
- }
-
- void setOnBackPressListener(OnBackPressListener onBackPressListener) {
- mOnBackPressListener = onBackPressListener;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KEYCODE_BACK && event.getAction() == ACTION_UP
- && mOnBackPressListener != null) {
- mOnBackPressListener.onBackPress();
- return true;
- } else {
- return super.dispatchKeyEvent(event);
- }
- }
-
- void setAppActions(ParceledListSlice<RemoteAction> actions) {
- if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()");
-
- boolean hasCustomActions = actions != null && !actions.getList().isEmpty();
- mPipControlsViewController.setCustomActions(
- hasCustomActions ? actions.getList() : Collections.emptyList());
- }
-
- interface OnBackPressListener {
- void onBackPress();
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
index 4e82bb557fb9..6f7cd82f8da0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlButtonView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuActionButton.java
@@ -31,64 +31,51 @@ import android.widget.TextView;
import com.android.wm.shell.R;
/**
- * A view containing PIP controls including fullscreen, close, and media controls.
+ * A View that represents Pip Menu action button, such as "Fullscreen" and "Close" as well custom
+ * (provided by the application in Pip) and media buttons.
*/
-public class PipControlButtonView extends RelativeLayout {
-
- private OnFocusChangeListener mFocusChangeListener;
- private ImageView mIconImageView;
- ImageView mButtonImageView;
- private TextView mDescriptionTextView;
+public class TvPipMenuActionButton extends RelativeLayout implements View.OnClickListener {
+ private final ImageView mIconImageView;
+ private final ImageView mButtonImageView;
+ private final TextView mDescriptionTextView;
private Animator mTextFocusGainAnimator;
private Animator mButtonFocusGainAnimator;
private Animator mTextFocusLossAnimator;
private Animator mButtonFocusLossAnimator;
+ private OnClickListener mOnClickListener;
- private final OnFocusChangeListener mInternalFocusChangeListener =
- new OnFocusChangeListener() {
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- startFocusGainAnimation();
- } else {
- startFocusLossAnimation();
- }
-
- if (mFocusChangeListener != null) {
- mFocusChangeListener.onFocusChange(PipControlButtonView.this, hasFocus);
- }
- }
- };
-
- public PipControlButtonView(Context context) {
+ public TvPipMenuActionButton(Context context) {
this(context, null, 0, 0);
}
- public PipControlButtonView(Context context, AttributeSet attrs) {
+ public TvPipMenuActionButton(Context context, AttributeSet attrs) {
this(context, attrs, 0, 0);
}
- public PipControlButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public TvPipMenuActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public PipControlButtonView(
+ public TvPipMenuActionButton(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- LayoutInflater inflater = (LayoutInflater) getContext()
+ final LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- inflater.inflate(R.layout.tv_pip_control_button, this);
+ inflater.inflate(R.layout.tv_pip_menu_action_button, this);
mIconImageView = findViewById(R.id.icon);
mButtonImageView = findViewById(R.id.button);
mDescriptionTextView = findViewById(R.id.desc);
- int[] values = new int[]{android.R.attr.src, android.R.attr.text};
- TypedArray typedArray = context.obtainStyledAttributes(attrs, values, defStyleAttr,
+ final int[] values = new int[]{android.R.attr.src, android.R.attr.text};
+ final TypedArray typedArray = context.obtainStyledAttributes(attrs, values, defStyleAttr,
defStyleRes);
setImageResource(typedArray.getResourceId(0, 0));
- setText(typedArray.getResourceId(1, 0));
+ final int textResId = typedArray.getResourceId(1, 0);
+ if (textResId != 0) {
+ setTextAndDescription(getContext().getString(textResId));
+ }
typedArray.recycle();
}
@@ -96,7 +83,13 @@ public class PipControlButtonView extends RelativeLayout {
@Override
public void onFinishInflate() {
super.onFinishInflate();
- mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
+ mButtonImageView.setOnFocusChangeListener((v, hasFocus) -> {
+ if (hasFocus) {
+ startFocusGainAnimation();
+ } else {
+ startFocusLossAnimation();
+ }
+ });
mTextFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
R.anim.tv_pip_controls_focus_gain_animation);
@@ -115,12 +108,19 @@ public class PipControlButtonView extends RelativeLayout {
@Override
public void setOnClickListener(OnClickListener listener) {
- mButtonImageView.setOnClickListener(listener);
+ // We do not want to set an OnClickListener to the TvPipMenuActionButton itself, but only to
+ // the ImageView. So let's "cash" the listener we've been passed here and set a "proxy"
+ // listener to the ImageView.
+ mOnClickListener = listener;
+ mButtonImageView.setOnClickListener(listener != null ? this : null);
}
@Override
- public void setOnFocusChangeListener(OnFocusChangeListener listener) {
- mFocusChangeListener = listener;
+ public void onClick(View v) {
+ if (mOnClickListener != null) {
+ // Pass the correct view - this.
+ mOnClickListener.onClick(this);
+ }
}
/**
@@ -142,21 +142,11 @@ public class PipControlButtonView extends RelativeLayout {
/**
* Sets the text for description the with the given string.
*/
- public void setText(CharSequence text) {
+ public void setTextAndDescription(CharSequence text) {
mButtonImageView.setContentDescription(text);
mDescriptionTextView.setText(text);
}
- /**
- * Sets the text for description the with the given resource id.
- */
- public void setText(int resId) {
- if (resId != 0) {
- mButtonImageView.setContentDescription(getContext().getString(resId));
- mDescriptionTextView.setText(resId);
- }
- }
-
private static void cancelAnimator(Animator animator) {
if (animator.isStarted()) {
animator.cancel();
@@ -187,8 +177,8 @@ public class PipControlButtonView extends RelativeLayout {
mTextFocusLossAnimator.start();
if (mButtonImageView.hasFocus()) {
// Button uses ripple that has the default animation for the focus changes.
- // Howevever, it doesn't expose the API to fade out while it is focused,
- // so we should manually run the fade out animation when PIP controls row loses focus.
+ // However, it doesn't expose the API to fade out while it is focused, so we should
+ // manually run the fade out animation when PIP controls row loses focus.
mButtonFocusLossAnimator.start();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 5d0d761abd93..9192cf14cd9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -19,38 +19,97 @@ package com.android.wm.shell.pip.tv;
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
import android.app.RemoteAction;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ParceledListSlice;
import android.util.Log;
import android.view.SurfaceControl;
+import androidx.annotation.Nullable;
+
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipMediaController;
import com.android.wm.shell.pip.PipMenuController;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Manages the visibility of the PiP Menu as user interacts with PiP.
*/
-public class TvPipMenuController implements PipMenuController {
+public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener {
private static final String TAG = "TvPipMenuController";
private static final boolean DEBUG = PipController.DEBUG;
private final Context mContext;
private final SystemWindows mSystemWindows;
private final PipBoundsState mPipBoundsState;
- private PipMenuView mMenuView;
- private PipController mPipController;
+
+ private Delegate mDelegate;
private SurfaceControl mLeash;
+ private TvPipMenuView mMenuView;
+
+ private final List<RemoteAction> mMediaActions = new ArrayList<>();
+ private final List<RemoteAction> mAppActions = new ArrayList<>();
public TvPipMenuController(Context context, PipBoundsState pipBoundsState,
- SystemWindows systemWindows) {
+ SystemWindows systemWindows, PipMediaController pipMediaController) {
mContext = context;
mPipBoundsState = pipBoundsState;
mSystemWindows = systemWindows;
+
+ // We need to "close" the menu the platform call for all the system dialogs to close (for
+ // example, on the Home button press).
+ final BroadcastReceiver closeSystemDialogsBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ hideMenu();
+ }
+ };
+ context.registerReceiver(closeSystemDialogsBroadcastReceiver,
+ new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
+ pipMediaController.addActionListener(this::onMediaActionsChanged);
}
- void attachPipController(PipController pipController) {
- mPipController = pipController;
+ void setDelegate(Delegate delegate) {
+ if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate);
+ if (mDelegate != null) {
+ throw new IllegalStateException(
+ "The delegate has already been set and should not change.");
+ }
+ if (delegate == null) {
+ throw new IllegalArgumentException("The delegate must not be null.");
+ }
+
+ mDelegate = delegate;
+ }
+
+ @Override
+ public void attach(SurfaceControl leash) {
+ if (mDelegate == null) {
+ throw new IllegalStateException("Delegate is not set.");
+ }
+
+ mLeash = leash;
+ attachPipMenuView();
+ }
+
+ private void attachPipMenuView() {
+ if (DEBUG) Log.d(TAG, "attachPipMenuView()");
+
+ if (mMenuView != null) {
+ detachPipMenuView();
+ }
+
+ mMenuView = new TvPipMenuView(mContext);
+ mMenuView.setListener(this);
+ mSystemWindows.addView(mMenuView,
+ getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+ 0, SHELL_ROOT_LAYER_PIP);
}
@Override
@@ -61,7 +120,8 @@ public class TvPipMenuController implements PipMenuController {
mSystemWindows.updateViewLayout(mMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE,
mPipBoundsState.getDisplayBounds().width(),
mPipBoundsState.getDisplayBounds().height()));
- mMenuView.showMenu();
+ maybeUpdateMenuViewActions();
+ mMenuView.show();
// By default, SystemWindows views are above everything else.
// Set the relative z-order so the menu is below PiP.
@@ -77,38 +137,18 @@ public class TvPipMenuController implements PipMenuController {
if (DEBUG) Log.d(TAG, "hideMenu()");
if (isMenuVisible()) {
- mMenuView.hideMenu();
- mPipController.resizePinnedStack(PipController.STATE_PIP);
+ mMenuView.hide();
+ mDelegate.movePipToNormalPosition();
}
}
@Override
- public void attach(SurfaceControl leash) {
- mLeash = leash;
- attachPipMenuView();
- }
-
- @Override
public void detach() {
hideMenu();
detachPipMenuView();
mLeash = null;
}
- private void attachPipMenuView() {
- if (DEBUG) Log.d(TAG, "attachPipMenuView()");
-
- if (mMenuView != null) {
- detachPipMenuView();
- }
-
- mMenuView = new PipMenuView(mContext, mPipController);
- mMenuView.setOnBackPressListener(this::hideMenu);
- mSystemWindows.addView(mMenuView,
- getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
- 0, SHELL_ROOT_LAYER_PIP);
- }
-
private void detachPipMenuView() {
if (DEBUG) Log.d(TAG, "detachPipMenuView()");
@@ -121,18 +161,65 @@ public class TvPipMenuController implements PipMenuController {
}
@Override
- public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
- if (DEBUG) Log.d(TAG, "setAppActions(), actions=" + appActions);
+ public void setAppActions(ParceledListSlice<RemoteAction> actions) {
+ if (DEBUG) Log.d(TAG, "setAppActions()");
+ updateAdditionalActionsList(mAppActions, actions.getList());
+ }
- if (mMenuView != null) {
- mMenuView.setAppActions(appActions);
+ private void onMediaActionsChanged(List<RemoteAction> actions) {
+ if (DEBUG) Log.d(TAG, "onMediaActionsChanged()");
+ updateAdditionalActionsList(mMediaActions, actions);
+ }
+
+ private void updateAdditionalActionsList(
+ List<RemoteAction> destination, @Nullable List<RemoteAction> source) {
+ final int number = source != null ? source.size() : 0;
+ if (number == 0 && destination.isEmpty()) {
+ // Nothing changed.
+ return;
+ }
+
+ destination.clear();
+ if (number > 0) {
+ destination.addAll(source);
+ }
+ maybeUpdateMenuViewActions();
+ }
+
+ private void maybeUpdateMenuViewActions() {
+ if (mMenuView == null) {
+ return;
+ }
+ if (!mAppActions.isEmpty()) {
+ mMenuView.setAdditionalActions(mAppActions);
} else {
- Log.w(TAG, "Cannot set remote actions, there is no View");
+ mMenuView.setAdditionalActions(mMediaActions);
}
}
@Override
public boolean isMenuVisible() {
- return mMenuView != null && mMenuView.getAlpha() == 1.0f;
+ return mMenuView != null && mMenuView.isVisible();
+ }
+
+ @Override
+ public void onBackPress() {
+ hideMenu();
+ }
+
+ @Override
+ public void onCloseButtonClick() {
+ mDelegate.closePip();
+ }
+
+ @Override
+ public void onFullscreenButtonClick() {
+ mDelegate.movePipToFullscreen();
+ }
+
+ interface Delegate {
+ void movePipToNormalPosition();
+ void movePipToFullscreen();
+ void closePip();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
new file mode 100644
index 000000000000..f7b76c1ec745
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -0,0 +1,235 @@
+/*
+ * 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.wm.shell.pip.tv;
+
+import static android.animation.AnimatorInflater.loadAnimator;
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
+
+import android.animation.Animator;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A View that represents Pip Menu on TV. It's responsible for displaying 2 ever-present Pip Menu
+ * actions: Fullscreen and Close, but could also display "additional" actions, that may be set via
+ * a {@link #setAdditionalActions(List)} call.
+ */
+public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
+ private static final String TAG = "TvPipMenuView";
+ private static final boolean DEBUG = PipController.DEBUG;
+
+ private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
+ private final Handler mUiThreadHandler;
+ private final Animator mFadeInAnimation;
+ private final Animator mFadeOutAnimation;
+ @Nullable private Listener mListener;
+
+ private final LinearLayout mActionButtonsContainer;
+ private final List<TvPipMenuActionButton> mAdditionalButtons = new ArrayList<>();
+
+ public TvPipMenuView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public TvPipMenuView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TvPipMenuView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public TvPipMenuView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ mUiThreadHandler = new Handler(Looper.getMainLooper());
+
+ inflate(context, R.layout.tv_pip_menu, this);
+
+ mActionButtonsContainer = findViewById(R.id.tv_pip_menu_action_buttons);
+ mActionButtonsContainer.findViewById(R.id.tv_pip_menu_fullscreen_button)
+ .setOnClickListener(this);
+ mActionButtonsContainer.findViewById(R.id.tv_pip_menu_close_button)
+ .setOnClickListener(this);
+
+ mFadeInAnimation = loadAnimator(mContext, R.anim.tv_pip_menu_fade_in_animation);
+ mFadeInAnimation.setTarget(mActionButtonsContainer);
+
+ mFadeOutAnimation = loadAnimator(mContext, R.anim.tv_pip_menu_fade_out_animation);
+ mFadeOutAnimation.setTarget(mActionButtonsContainer);
+ }
+
+ void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ void show() {
+ if (DEBUG) Log.d(TAG, "show()");
+
+ mFadeInAnimation.start();
+ setAlpha(1.0f);
+ grantWindowFocus(true);
+ }
+
+ void hide() {
+ if (DEBUG) Log.d(TAG, "hide()");
+
+ mFadeOutAnimation.start();
+ setAlpha(0.0f);
+ grantWindowFocus(false);
+ }
+
+ boolean isVisible() {
+ return getAlpha() == 1.0f;
+ }
+
+ private void grantWindowFocus(boolean grantFocus) {
+ if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ getViewRootImpl().getInputToken(), grantFocus);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus", e);
+ }
+ }
+
+ void setAdditionalActions(List<RemoteAction> actions) {
+ if (DEBUG) Log.d(TAG, "setAdditionalActions()");
+
+ // Make sure we exactly as many additional buttons as we have actions to display.
+ final int actionsNumber = actions.size();
+ int buttonsNumber = mAdditionalButtons.size();
+ if (actionsNumber > buttonsNumber) {
+ final LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+ // Add buttons until we have enough to display all of the actions.
+ while (actionsNumber > buttonsNumber) {
+ final TvPipMenuActionButton button = (TvPipMenuActionButton) layoutInflater.inflate(
+ R.layout.tv_pip_menu_additional_action_button, mActionButtonsContainer,
+ false);
+ button.setOnClickListener(this);
+
+ mActionButtonsContainer.addView(button);
+ mAdditionalButtons.add(button);
+
+ buttonsNumber++;
+ }
+ } else if (actionsNumber < buttonsNumber) {
+ // Hide buttons until we as many as the actions.
+ while (actionsNumber < buttonsNumber) {
+ final View button = mAdditionalButtons.get(buttonsNumber - 1);
+ button.setVisibility(View.GONE);
+ button.setTag(null);
+
+ buttonsNumber--;
+ }
+ }
+
+ // "Assign" actions to the buttons.
+ for (int index = 0; index < actionsNumber; index++) {
+ final RemoteAction action = actions.get(index);
+ final TvPipMenuActionButton button = mAdditionalButtons.get(index);
+ button.setVisibility(View.VISIBLE); // Ensure the button is visible.
+ button.setTextAndDescription(action.getContentDescription());
+ button.setEnabled(action.isEnabled());
+ button.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
+ button.setTag(action);
+
+ action.getIcon().loadDrawableAsync(mContext, drawable -> {
+ drawable.setTint(Color.WHITE);
+ button.setImageDrawable(drawable);
+ }, mUiThreadHandler);
+ }
+ }
+
+ @Nullable
+ SurfaceControl getWindowSurfaceControl() {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ final SurfaceControl out = root.getSurfaceControl();
+ if (out != null && out.isValid()) {
+ return out;
+ }
+ return null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (mListener == null) return;
+
+ final int id = v.getId();
+ if (id == R.id.tv_pip_menu_fullscreen_button) {
+ mListener.onFullscreenButtonClick();
+ } else if (id == R.id.tv_pip_menu_close_button) {
+ mListener.onCloseButtonClick();
+ } else {
+ // This should be an "additional action"
+ final RemoteAction action = (RemoteAction) v.getTag();
+ if (action != null) {
+ try {
+ action.getActionIntent().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "Failed to send action", e);
+ }
+ } else {
+ Log.w(TAG, "RemoteAction is null");
+ }
+ }
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK
+ && mListener != null) {
+ mListener.onBackPress();
+ return true;
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ interface Listener {
+ void onBackPress();
+ void onCloseButtonClick();
+ void onFullscreenButtonClick();
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 5125a3972cf4..796c8c4a6ad0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -31,6 +31,10 @@ const val TEST_APP_PIP_MENU_ACTION_CLEAR = "Clear"
// Test App > Ime Activity
const val TEST_APP_IME_ACTIVITY_LABEL = "ImeApp"
+const val TEST_APP_IME_ACTIVITY_ACTION_OPEN_IME =
+ "com.android.wm.shell.flicker.testapp.action.OPEN_IME"
+const val TEST_APP_IME_ACTIVITY_ACTION_CLOSE_IME =
+ "com.android.wm.shell.flicker.testapp.action.CLOSE_IME"
// Test App > Test Activity
const val TEST_APP_FIXED_ACTIVITY_LABEL = "FixedApp"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
index 6fd1df3b3f30..f8efd0e9c761 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/BaseAppHelper.kt
@@ -62,8 +62,9 @@ abstract class BaseAppHelper(
val ui: UiObject2?
get() = uiDevice.findObject(appSelector)
- fun launchViaIntent(stringExtras: Map<String, String> = mapOf()) {
+ fun launchViaIntent(action: String? = null, stringExtras: Map<String, String> = mapOf()) {
val intent = openAppIntent
+ intent.action = action
stringExtras.forEach() {
intent.putExtra(it.key, it.value)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index c546a4d18027..eb20d73cdcd1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -20,6 +20,8 @@ import android.app.Instrumentation
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_ACTION_CLOSE_IME
+import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_ACTION_OPEN_IME
import com.android.wm.shell.flicker.TEST_APP_IME_ACTIVITY_LABEL
import com.android.wm.shell.flicker.testapp.Components
import org.junit.Assert
@@ -32,15 +34,27 @@ open class ImeAppHelper(
Components.ImeActivity()
) {
fun openIME() {
- val editText = uiDevice.wait(
- Until.findObject(By.res(getPackage(), "plain_text_input")),
- FIND_TIMEOUT)
- Assert.assertNotNull("Text field not found, this usually happens when the device " +
- "was left in an unknown state (e.g. in split screen)", editText)
- editText.click()
+ if (!isTelevision) {
+ val editText = uiDevice.wait(
+ Until.findObject(By.res(getPackage(), "plain_text_input")),
+ FIND_TIMEOUT)
+ Assert.assertNotNull("Text field not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", editText)
+ editText.click()
+ } else {
+ // If we do the same thing as above - editText.click() - on TV, that's going to force TV
+ // into the touch mode. We really don't want that.
+ launchViaIntent(action = TEST_APP_IME_ACTIVITY_ACTION_OPEN_IME)
+ }
}
fun closeIME() {
- uiDevice.pressBack()
+ if (!isTelevision) {
+ uiDevice.pressBack()
+ } else {
+ // While pressing the back button should close the IME on TV as well, it may also lead
+ // to the app closing. So let's instead just ask the app to close the IME.
+ launchViaIntent(action = TEST_APP_IME_ACTIVITY_ACTION_CLOSE_IME)
+ }
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
index 66efb5ae3c2d..6105f50562d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipMenuTests.kt
@@ -208,8 +208,8 @@ class TvPipMenuTests : TvPipTestBase() {
@Test
fun pipMenu_customActions_override_mediaControls() {
// Start media session before entering PiP with custom actions.
- testApp.clickStartMediaSessionButton()
testApp.checkWithCustomActionsCheckbox()
+ testApp.clickStartMediaSessionButton()
enterPip_openMenu_assertShown()
// PiP menu should contain "No-Op", "Off" and "Clear" buttons for the custom actions...
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
index 587b5510b0b4..1b73920046dc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvUtils.kt
@@ -26,78 +26,109 @@ import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
/** Id of the root view in the com.android.wm.shell.pip.tv.PipMenuActivity */
private const val TV_PIP_MENU_ROOT_ID = "tv_pip_menu"
-private const val TV_PIP_MENU_CONTROLS_ID = "pip_controls"
-private const val TV_PIP_MENU_CLOSE_BUTTON_ID = "close_button"
-private const val TV_PIP_MENU_FULLSCREEN_BUTTON_ID = "full_button"
+private const val TV_PIP_MENU_BUTTONS_CONTAINER_ID = "tv_pip_menu_action_buttons"
+private const val TV_PIP_MENU_CLOSE_BUTTON_ID = "tv_pip_menu_close_button"
+private const val TV_PIP_MENU_FULLSCREEN_BUTTON_ID = "tv_pip_menu_fullscreen_button"
private const val FOCUS_ATTEMPTS = 10
private const val WAIT_TIME_MS = 3_000L
+private val TV_PIP_MENU_SELECTOR =
+ By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_ROOT_ID)
+private val TV_PIP_MENU_BUTTONS_CONTAINER_SELECTOR =
+ By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_BUTTONS_CONTAINER_ID)
private val TV_PIP_MENU_CLOSE_BUTTON_SELECTOR =
By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_CLOSE_BUTTON_ID)
private val TV_PIP_MENU_FULLSCREEN_BUTTON_SELECTOR =
By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_FULLSCREEN_BUTTON_ID)
-private val tvPipMenuSelector = By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_ROOT_ID)
-
-fun UiDevice.pressWindowKey() = pressKeyCode(KeyEvent.KEYCODE_WINDOW)
-
fun UiDevice.waitForTvPipMenu(): UiObject2? =
- wait(Until.findObject(tvPipMenuSelector), WAIT_TIME_MS)
+ wait(Until.findObject(TV_PIP_MENU_SELECTOR), WAIT_TIME_MS)
-fun UiDevice.waitForTvPipMenuToClose(): Boolean = wait(Until.gone(tvPipMenuSelector), WAIT_TIME_MS)
+fun UiDevice.waitForTvPipMenuToClose(): Boolean =
+ wait(Until.gone(TV_PIP_MENU_SELECTOR), WAIT_TIME_MS)
fun UiDevice.findTvPipMenuControls(): UiObject2? =
- findObject(tvPipMenuSelector)
- ?.findObject(By.res(SYSTEM_UI_PACKAGE_NAME, TV_PIP_MENU_CONTROLS_ID))
+ findTvPipMenuElement(TV_PIP_MENU_BUTTONS_CONTAINER_SELECTOR)
fun UiDevice.findTvPipMenuCloseButton(): UiObject2? =
- findObject(tvPipMenuSelector)?.findObject(TV_PIP_MENU_CLOSE_BUTTON_SELECTOR)
+ findTvPipMenuElement(TV_PIP_MENU_CLOSE_BUTTON_SELECTOR)
+
+fun UiDevice.findTvPipMenuFullscreenButton(): UiObject2? =
+ findTvPipMenuElement(TV_PIP_MENU_FULLSCREEN_BUTTON_SELECTOR)
+
+fun UiDevice.findTvPipMenuElementWithDescription(desc: String): UiObject2? =
+ findTvPipMenuElement(By.desc(desc))
+
+private fun UiDevice.findTvPipMenuElement(selector: BySelector): UiObject2? =
+ findObject(TV_PIP_MENU_SELECTOR)?.findObject(selector)
+
+fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? {
+ // Ideally, we'd want to wait for an element with the given description that has the Pip Menu as
+ // its parent, but the API does not allow us to construct a query exactly that way.
+ // So instead we'll wait for a Pip Menu that has the element, which we are looking for, as a
+ // descendant and then retrieve the element from the menu and return to the caller of this
+ // method.
+ val elementSelector = By.desc(desc)
+ val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR).hasDescendant(elementSelector)
+
+ return wait(Until.findObject(menuContainingElementSelector), WAIT_TIME_MS)
+ ?.findObject(elementSelector)
+}
+
+fun UiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(desc: String): Boolean? {
+ val elementSelector = By.desc(desc)
+ val menuContainingElementSelector = By.copy(TV_PIP_MENU_SELECTOR).hasDescendant(elementSelector)
+
+ return wait(Until.gone(menuContainingElementSelector), WAIT_TIME_MS)
+}
fun UiDevice.clickTvPipMenuCloseButton() {
- focusOnObjectInTvPipMenu(TV_PIP_MENU_CLOSE_BUTTON_SELECTOR) ||
+ focusOnAndClickTvPipMenuElement(TV_PIP_MENU_CLOSE_BUTTON_SELECTOR) ||
error("Could not focus on the Close button")
- pressDPadCenter()
}
-fun UiDevice.findTvPipMenuFullscreenButton(): UiObject2? =
- findObject(tvPipMenuSelector)?.findObject(TV_PIP_MENU_FULLSCREEN_BUTTON_SELECTOR)
-
fun UiDevice.clickTvPipMenuFullscreenButton() {
- focusOnObjectInTvPipMenu(TV_PIP_MENU_FULLSCREEN_BUTTON_SELECTOR) ||
+ focusOnAndClickTvPipMenuElement(TV_PIP_MENU_FULLSCREEN_BUTTON_SELECTOR) ||
error("Could not focus on the Fullscreen button")
- pressDPadCenter()
}
-fun UiDevice.findTvPipMenuElementWithDescription(desc: String): UiObject2? =
- findObject(tvPipMenuSelector)?.findObject(By.desc(desc).pkg(SYSTEM_UI_PACKAGE_NAME))
-
fun UiDevice.clickTvPipMenuElementWithDescription(desc: String) {
- focusOnObjectInTvPipMenu(By.desc(desc).pkg(SYSTEM_UI_PACKAGE_NAME)) ||
+ focusOnAndClickTvPipMenuElement(By.desc(desc).pkg(SYSTEM_UI_PACKAGE_NAME)) ||
error("Could not focus on the Pip menu object with \"$desc\" description")
- pressDPadCenter()
+ // So apparently Accessibility framework on TV is not very reliable and sometimes the state of
+ // the tree of accessibility nodes as seen by the accessibility clients kind of lags behind of
+ // the "real" state of the "UI tree". It seems, however, that moving focus around the tree
+ // forces the AccessibilityNodeInfo tree to get properly updated.
+ // So since we suspect that clicking on a Pip Menu element may cause some UI changes and we want
+ // those changes to be seen by the UiAutomator, which is using Accessibility framework under the
+ // hood for inspecting UI, we'll move the focus around a little.
+ moveFocus()
}
-fun UiDevice.waitForTvPipMenuElementWithDescription(desc: String): UiObject2? {
- val buttonSelector = By.desc(desc)
- val menuWithButtonSelector = By.copy(tvPipMenuSelector).hasDescendant(buttonSelector)
- return wait(Until.findObject(menuWithButtonSelector), WAIT_TIME_MS)
- ?.findObject(buttonSelector)
-}
-
-fun UiDevice.waitUntilTvPipMenuElementWithDescriptionIsGone(desc: String): Boolean? =
- wait(Until.gone(By.copy(tvPipMenuSelector).hasDescendant(By.desc(desc))), WAIT_TIME_MS)
+private fun UiDevice.focusOnAndClickTvPipMenuElement(selector: BySelector): Boolean {
+ repeat(FOCUS_ATTEMPTS) {
+ val element = findTvPipMenuElement(selector)
+ ?: error("The Pip Menu element we try to focus on is gone.")
+
+ if (element.isFocusedOrHasFocusedChild) {
+ pressDPadCenter()
+ return true
+ }
+
+ findTvPipMenuElement(By.focused(true))?.let { focused ->
+ if (element.visibleCenter.x < focused.visibleCenter.x)
+ pressDPadLeft() else pressDPadRight()
+ waitForIdle()
+ } ?: error("Pip menu does not contain a focused element")
+ }
-fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
- height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
+ return false
}
-val UiObject2.isFocusedOrHasFocusedChild: Boolean
- get() = isFocused || findObject(By.focused(true)) != null
-
fun UiDevice.closeTvPipWindow() {
// Check if Pip menu is Open. If it's not, open it.
- if (findObject(tvPipMenuSelector) == null) {
+ if (findObject(TV_PIP_MENU_SELECTOR) == null) {
pressWindowKey()
waitForTvPipMenu() ?: error("Could not open Pip menu")
}
@@ -106,17 +137,25 @@ fun UiDevice.closeTvPipWindow() {
waitForTvPipMenuToClose()
}
-private fun UiDevice.focusOnObjectInTvPipMenu(objectSelector: BySelector): Boolean {
- repeat(FOCUS_ATTEMPTS) {
- val menu = findObject(tvPipMenuSelector) ?: error("Pip Menu is now shown")
- val objectToFocus = menu.findObject(objectSelector)
- .apply { if (isFocusedOrHasFocusedChild) return true }
- ?: error("The object we try to focus on is gone.")
- val currentlyFocused = menu.findObject(By.focused(true))
- ?: error("Pip menu does not contain a focused element")
- if (objectToFocus.visibleCenter.x < currentlyFocused.visibleCenter.x)
- pressDPadLeft() else pressDPadRight()
- waitForIdle()
- }
- return false
-} \ No newline at end of file
+/**
+ * Simply presses the D-Pad Left and Right buttons once, which should move the focus on the screen,
+ * which should cause Accessibility events to be fired, which should, hopefully, properly update
+ * AccessibilityNodeInfo tree dispatched by the platform to the Accessibility services, one of which
+ * is the UiAutomator.
+ */
+private fun UiDevice.moveFocus() {
+ waitForIdle()
+ pressDPadLeft()
+ waitForIdle()
+ pressDPadRight()
+ waitForIdle()
+}
+
+fun UiDevice.pressWindowKey() = pressKeyCode(KeyEvent.KEYCODE_WINDOW)
+
+fun UiObject2.isFullscreen(uiDevice: UiDevice): Boolean = visibleBounds.run {
+ height() == uiDevice.displayHeight && width() == uiDevice.displayWidth
+}
+
+val UiObject2.isFocusedOrHasFocusedChild: Boolean
+ get() = isFocused || findObject(By.focused(true)) != null
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
index 28ed3431db62..5549330df766 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -53,6 +53,7 @@
<activity android:name=".ImeActivity"
android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity"
android:label="ImeApp"
+ android:launchMode="singleTop"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java
index 856728715c1c..59c64a1345ab 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java
@@ -17,10 +17,21 @@
package com.android.wm.shell.flicker.testapp;
import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
+import android.view.View;
import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
public class ImeActivity extends Activity {
+ private static final String ACTION_OPEN_IME =
+ "com.android.wm.shell.flicker.testapp.action.OPEN_IME";
+ private static final String ACTION_CLOSE_IME =
+ "com.android.wm.shell.flicker.testapp.action.CLOSE_IME";
+
+ private InputMethodManager mImm;
+ private View mEditText;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -29,5 +40,27 @@ public class ImeActivity extends Activity {
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
getWindow().setAttributes(p);
setContentView(R.layout.activity_ime);
+
+ mEditText = findViewById(R.id.plain_text_input);
+ mImm = getSystemService(InputMethodManager.class);
+
+ handleIntent(getIntent());
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent intent) {
+ final String action = intent.getAction();
+ if (ACTION_OPEN_IME.equals(action)) {
+ mEditText.requestFocus();
+ mImm.showSoftInput(mEditText, InputMethodManager.SHOW_FORCED);
+ } else if (ACTION_CLOSE_IME.equals(action)) {
+ mImm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
+ mEditText.clearFocus();
+ }
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
index 069305212958..bde04b604c79 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java
@@ -71,7 +71,7 @@ public class BubbleTest extends ShellTestCase {
Intent target = new Intent(mContext, BubblesTestActivity.class);
Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
- PendingIntent.getActivity(mContext, 0, target, 0),
+ PendingIntent.getActivity(mContext, 0, target, PendingIntent.FLAG_MUTABLE),
Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble))
.build();
when(mSbn.getNotification()).thenReturn(mNotif);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index acb74f415f41..815ffdeade45 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -814,6 +814,18 @@ void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
mCanvas->drawDrawable(drawable.get());
}
+void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect) {
+ sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
+ new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
+ runtimeEffect));
+ mCanvas->drawDrawable(drawable.get());
+}
+
void SkiaCanvas::drawPicture(const SkPicture& picture) {
// TODO: Change to mCanvas->drawPicture()? SkCanvas::drawPicture seems to be
// where the logic is for playback vs. ref picture. Using picture.playback here
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 584321ec9094..fa7d373308d3 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -147,6 +147,12 @@ public:
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override;
+ virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
diff --git a/libs/hwui/canvas/CanvasOpTypes.h b/libs/hwui/canvas/CanvasOpTypes.h
index f0aa7774a6cc..cde50bd66a15 100644
--- a/libs/hwui/canvas/CanvasOpTypes.h
+++ b/libs/hwui/canvas/CanvasOpTypes.h
@@ -42,6 +42,7 @@ enum class CanvasOpType : int8_t {
DrawRoundRectProperty,
DrawDoubleRoundRect,
DrawCircleProperty,
+ DrawRippleProperty,
DrawCircle,
DrawOval,
DrawArc,
diff --git a/libs/hwui/canvas/CanvasOps.h b/libs/hwui/canvas/CanvasOps.h
index 62c26c7b6f6a..ea9fea974d06 100644
--- a/libs/hwui/canvas/CanvasOps.h
+++ b/libs/hwui/canvas/CanvasOps.h
@@ -23,6 +23,7 @@
#include <SkVertices.h>
#include <SkImage.h>
#include <SkPicture.h>
+#include <SkRuntimeEffect.h>
#include <hwui/Bitmap.h>
#include <log/log.h>
#include "CanvasProperty.h"
@@ -142,6 +143,42 @@ struct CanvasOp<CanvasOpType::DrawCircleProperty> {
ASSERT_DRAWABLE()
};
+template<>
+struct CanvasOp<CanvasOpType::DrawRippleProperty> {
+ sp<uirenderer::CanvasPropertyPrimitive> x;
+ sp<uirenderer::CanvasPropertyPrimitive> y;
+ sp<uirenderer::CanvasPropertyPrimitive> radius;
+ sp<uirenderer::CanvasPropertyPaint> paint;
+ sp<uirenderer::CanvasPropertyPrimitive> progress;
+ sk_sp<SkRuntimeEffect> effect;
+
+ void draw(SkCanvas* canvas) const {
+ SkRuntimeShaderBuilder runtimeEffectBuilder(effect);
+
+ SkRuntimeShaderBuilder::BuilderUniform center = runtimeEffectBuilder.uniform("in_origin");
+ if (center.fVar != nullptr) {
+ center = SkV2{x->value, y->value};
+ }
+
+ SkRuntimeShaderBuilder::BuilderUniform radiusU =
+ runtimeEffectBuilder.uniform("in_maxRadius");
+ if (radiusU.fVar != nullptr) {
+ radiusU = radius->value;
+ }
+
+ SkRuntimeShaderBuilder::BuilderUniform progressU =
+ runtimeEffectBuilder.uniform("in_progress");
+ if (progressU.fVar != nullptr) {
+ progressU = progress->value;
+ }
+
+ SkPaint paintMod = paint->value;
+ paintMod.setShader(runtimeEffectBuilder.makeShader(nullptr, false));
+ canvas->drawCircle(x->value, y->value, radius->value, paintMod);
+ }
+ ASSERT_DRAWABLE()
+};
+
template <>
struct CanvasOp<CanvasOpType::DrawColor> {
SkColor4f color;
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 11fa3223a9c8..d0c996bee449 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -31,6 +31,7 @@
class SkAnimatedImage;
class SkCanvasState;
+class SkRuntimeEffect;
class SkVertices;
namespace minikin {
@@ -133,6 +134,12 @@ public:
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) = 0;
+ virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp
index 688913471913..b3f7627b1cf7 100644
--- a/libs/hwui/hwui/ImageDecoder.cpp
+++ b/libs/hwui/hwui/ImageDecoder.cpp
@@ -17,11 +17,19 @@
#include "ImageDecoder.h"
#include <hwui/Bitmap.h>
+#include <log/log.h>
#include <SkAndroidCodec.h>
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
#include <SkCanvas.h>
+#include <SkEncodedOrigin.h>
+#include <SkFilterQuality.h>
#include <SkPaint.h>
+#undef LOG_TAG
+#define LOG_TAG "ImageDecoder"
+
using namespace android;
sk_sp<SkColorSpace> ImageDecoder::getDefaultColorSpace() const {
@@ -44,17 +52,29 @@ ImageDecoder::ImageDecoder(std::unique_ptr<SkAndroidCodec> codec, sk_sp<SkPngChu
, mOutColorType(mCodec->computeOutputColorType(kN32_SkColorType))
, mUnpremultipliedRequired(false)
, mOutColorSpace(getDefaultColorSpace())
- , mSampleSize(1)
{
mTargetSize = swapWidthHeight() ? SkISize { mDecodeSize.height(), mDecodeSize.width() }
: mDecodeSize;
+ this->rewind();
}
+ImageDecoder::~ImageDecoder() = default;
+
SkAlphaType ImageDecoder::getOutAlphaType() const {
return opaque() ? kOpaque_SkAlphaType
: mUnpremultipliedRequired ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
}
+static SkISize swapped(const SkISize& size) {
+ return SkISize { size.height(), size.width() };
+}
+
+static bool requires_matrix_scaling(bool swapWidthHeight, const SkISize& decodeSize,
+ const SkISize& targetSize) {
+ return (swapWidthHeight && decodeSize != swapped(targetSize))
+ || (!swapWidthHeight && decodeSize != targetSize);
+}
+
bool ImageDecoder::setTargetSize(int width, int height) {
if (width <= 0 || height <= 0) {
return false;
@@ -78,17 +98,21 @@ bool ImageDecoder::setTargetSize(int width, int height) {
}
}
- SkISize targetSize = { width, height };
- SkISize decodeSize = swapWidthHeight() ? SkISize { height, width } : targetSize;
+ const bool swap = swapWidthHeight();
+ const SkISize targetSize = { width, height };
+ SkISize decodeSize = swap ? SkISize { height, width } : targetSize;
int sampleSize = mCodec->computeSampleSize(&decodeSize);
- if (decodeSize != targetSize && mUnpremultipliedRequired && !opaque()) {
- return false;
+ if (mUnpremultipliedRequired && !opaque()) {
+ // Allow using a matrix to handle orientation, but not scaling.
+ if (requires_matrix_scaling(swap, decodeSize, targetSize)) {
+ return false;
+ }
}
mTargetSize = targetSize;
mDecodeSize = decodeSize;
- mSampleSize = sampleSize;
+ mOptions.fSampleSize = sampleSize;
return true;
}
@@ -137,8 +161,10 @@ bool ImageDecoder::setOutColorType(SkColorType colorType) {
}
bool ImageDecoder::setUnpremultipliedRequired(bool required) {
- if (required && !opaque() && mDecodeSize != mTargetSize) {
- return false;
+ if (required && !opaque()) {
+ if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
+ return false;
+ }
}
mUnpremultipliedRequired = required;
return true;
@@ -176,26 +202,202 @@ int ImageDecoder::height() const {
}
bool ImageDecoder::opaque() const {
- return mCodec->getInfo().alphaType() == kOpaque_SkAlphaType;
+ return mCurrentFrameIsOpaque;
}
bool ImageDecoder::gray() const {
return mCodec->getInfo().colorType() == kGray_8_SkColorType;
}
+bool ImageDecoder::isAnimated() {
+ return mCodec->codec()->getFrameCount() > 1;
+}
+
+int ImageDecoder::currentFrame() const {
+ return mOptions.fFrameIndex;
+}
+
+bool ImageDecoder::rewind() {
+ mOptions.fFrameIndex = 0;
+ mOptions.fPriorFrame = SkCodec::kNoFrame;
+ mCurrentFrameIsIndependent = true;
+ mCurrentFrameIsOpaque = mCodec->getInfo().isOpaque();
+ mRestoreState = RestoreState::kDoNothing;
+ mRestoreFrame = nullptr;
+
+ // TODO: Rewind the input now instead of in the next call to decode, and
+ // plumb through whether rewind succeeded.
+ return true;
+}
+
+bool ImageDecoder::advanceFrame() {
+ const int frameIndex = ++mOptions.fFrameIndex;
+ const int frameCount = mCodec->codec()->getFrameCount();
+ if (frameIndex >= frameCount) {
+ // Prevent overflow from repeated calls to advanceFrame.
+ mOptions.fFrameIndex = frameCount;
+ return false;
+ }
+
+ SkCodec::FrameInfo frameInfo;
+ if (!mCodec->codec()->getFrameInfo(frameIndex, &frameInfo)
+ || !frameInfo.fFullyReceived) {
+ // Mark the decoder as finished, requiring a rewind.
+ mOptions.fFrameIndex = frameCount;
+ return false;
+ }
+
+ mCurrentFrameIsIndependent = frameInfo.fRequiredFrame == SkCodec::kNoFrame;
+ mCurrentFrameIsOpaque = frameInfo.fAlphaType == kOpaque_SkAlphaType;
+
+ if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kRestorePrevious) {
+ switch (mRestoreState) {
+ case RestoreState::kDoNothing:
+ case RestoreState::kNeedsRestore:
+ mRestoreState = RestoreState::kFirstRPFrame;
+ break;
+ case RestoreState::kFirstRPFrame:
+ mRestoreState = RestoreState::kRPFrame;
+ break;
+ case RestoreState::kRPFrame:
+ // Unchanged.
+ break;
+ }
+ } else { // New frame is not restore previous
+ switch (mRestoreState) {
+ case RestoreState::kFirstRPFrame:
+ case RestoreState::kRPFrame:
+ mRestoreState = RestoreState::kNeedsRestore;
+ break;
+ case RestoreState::kNeedsRestore:
+ mRestoreState = RestoreState::kDoNothing;
+ mRestoreFrame = nullptr;
+ [[fallthrough]];
+ case RestoreState::kDoNothing:
+ mOptions.fPriorFrame = frameIndex - 1;
+ break;
+ }
+ }
+
+ return true;
+}
+
+SkCodec::FrameInfo ImageDecoder::getCurrentFrameInfo() {
+ LOG_ALWAYS_FATAL_IF(finished());
+
+ auto dims = mCodec->codec()->dimensions();
+ SkCodec::FrameInfo info;
+ if (!mCodec->codec()->getFrameInfo(mOptions.fFrameIndex, &info)) {
+ // SkCodec may return false for a non-animated image. Provide defaults.
+ info.fRequiredFrame = SkCodec::kNoFrame;
+ info.fDuration = 0;
+ info.fFullyReceived = true;
+ info.fAlphaType = mCodec->codec()->getInfo().alphaType();
+ info.fHasAlphaWithinBounds = info.fAlphaType != kOpaque_SkAlphaType;
+ info.fDisposalMethod = SkCodecAnimation::DisposalMethod::kKeep;
+ info.fBlend = SkCodecAnimation::Blend::kSrc;
+ info.fFrameRect = SkIRect::MakeSize(dims);
+ }
+
+ if (auto origin = mCodec->codec()->getOrigin(); origin != kDefault_SkEncodedOrigin) {
+ if (SkEncodedOriginSwapsWidthHeight(origin)) {
+ dims = swapped(dims);
+ }
+ auto matrix = SkEncodedOriginToMatrix(origin, dims.width(), dims.height());
+ auto rect = SkRect::Make(info.fFrameRect);
+ LOG_ALWAYS_FATAL_IF(!matrix.mapRect(&rect));
+ rect.roundIn(&info.fFrameRect);
+ }
+ return info;
+}
+
+bool ImageDecoder::finished() const {
+ return mOptions.fFrameIndex >= mCodec->codec()->getFrameCount();
+}
+
SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
+ // This was checked inside setTargetSize, but it's possible the first frame
+ // was opaque, so that method succeeded, but after calling advanceFrame, the
+ // current frame is not opaque.
+ if (mUnpremultipliedRequired && !opaque()) {
+ // Allow using a matrix to handle orientation, but not scaling.
+ if (requires_matrix_scaling(swapWidthHeight(), mDecodeSize, mTargetSize)) {
+ return SkCodec::kInvalidScale;
+ }
+ }
+
void* decodePixels = pixels;
size_t decodeRowBytes = rowBytes;
- auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
- getOutputColorSpace());
+ const auto decodeInfo = SkImageInfo::Make(mDecodeSize, mOutColorType, getOutAlphaType(),
+ getOutputColorSpace());
+ const auto outputInfo = getOutputInfo();
+ switch (mRestoreState) {
+ case RestoreState::kFirstRPFrame:{
+ // This frame is marked kRestorePrevious. The prior frame should be in
+ // |pixels|, and it is what we'll restore after each consecutive
+ // kRestorePrevious frame. Cache it now.
+ if (!(mRestoreFrame = Bitmap::allocateHeapBitmap(outputInfo))) {
+ return SkCodec::kInternalError;
+ }
+
+ const uint8_t* srcRow = static_cast<uint8_t*>(pixels);
+ uint8_t* dstRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
+ for (int y = 0; y < outputInfo.height(); y++) {
+ memcpy(dstRow, srcRow, outputInfo.minRowBytes());
+ srcRow += rowBytes;
+ dstRow += mRestoreFrame->rowBytes();
+ }
+ break;
+ }
+ case RestoreState::kRPFrame:
+ case RestoreState::kNeedsRestore:
+ // Restore the cached frame. It's possible that the client skipped decoding a frame, so
+ // we never cached it.
+ if (mRestoreFrame) {
+ const uint8_t* srcRow = static_cast<uint8_t*>(mRestoreFrame->pixels());
+ uint8_t* dstRow = static_cast<uint8_t*>(pixels);
+ for (int y = 0; y < outputInfo.height(); y++) {
+ memcpy(dstRow, srcRow, outputInfo.minRowBytes());
+ srcRow += mRestoreFrame->rowBytes();
+ dstRow += rowBytes;
+ }
+ }
+ break;
+ case RestoreState::kDoNothing:
+ break;
+ }
+
// Used if we need a temporary before scaling or subsetting.
// FIXME: Use scanline decoding on only a couple lines to save memory. b/70709380.
SkBitmap tmp;
const bool scale = mDecodeSize != mTargetSize;
const auto origin = mCodec->codec()->getOrigin();
const bool handleOrigin = origin != kDefault_SkEncodedOrigin;
+ SkMatrix outputMatrix;
if (scale || handleOrigin || mCropRect) {
- if (!tmp.setInfo(decodeInfo)) {
+ if (mCropRect) {
+ outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop);
+ }
+
+ int targetWidth = mTargetSize.width();
+ int targetHeight = mTargetSize.height();
+ if (handleOrigin) {
+ outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight));
+ if (SkEncodedOriginSwapsWidthHeight(origin)) {
+ std::swap(targetWidth, targetHeight);
+ }
+ }
+ if (scale) {
+ float scaleX = (float) targetWidth / mDecodeSize.width();
+ float scaleY = (float) targetHeight / mDecodeSize.height();
+ outputMatrix.preScale(scaleX, scaleY);
+ }
+ // It's possible that this portion *does* have alpha, even if the
+ // composed frame does not. In that case, the SkBitmap needs to have
+ // alpha so it blends properly.
+ if (!tmp.setInfo(decodeInfo.makeAlphaType(mUnpremultipliedRequired ? kUnpremul_SkAlphaType
+ : kPremul_SkAlphaType)))
+ {
return SkCodec::kInternalError;
}
if (!Bitmap::allocateHeapBitmap(&tmp)) {
@@ -203,15 +405,28 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
}
decodePixels = tmp.getPixels();
decodeRowBytes = tmp.rowBytes();
+
+ if (!mCurrentFrameIsIndependent) {
+ SkMatrix inverse;
+ if (outputMatrix.invert(&inverse)) {
+ SkCanvas canvas(tmp, SkCanvas::ColorBehavior::kLegacy);
+ canvas.setMatrix(inverse);
+ SkPaint paint;
+ paint.setFilterQuality(kLow_SkFilterQuality); // bilinear
+ SkBitmap priorFrame;
+ priorFrame.installPixels(outputInfo, pixels, rowBytes);
+ canvas.drawBitmap(priorFrame, 0, 0, &paint);
+ } else {
+ ALOGE("Failed to invert matrix!");
+ }
+ }
}
- SkAndroidCodec::AndroidOptions options;
- options.fSampleSize = mSampleSize;
- auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &options);
+ auto result = mCodec->getAndroidPixels(decodeInfo, decodePixels, decodeRowBytes, &mOptions);
if (scale || handleOrigin || mCropRect) {
SkBitmap scaledBm;
- if (!scaledBm.installPixels(getOutputInfo(), pixels, rowBytes)) {
+ if (!scaledBm.installPixels(outputInfo, pixels, rowBytes)) {
return SkCodec::kInternalError;
}
@@ -220,26 +435,6 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) {
paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
- SkMatrix outputMatrix;
- if (mCropRect) {
- outputMatrix.setTranslate(-mCropRect->fLeft, -mCropRect->fTop);
- }
-
- int targetWidth = mTargetSize.width();
- int targetHeight = mTargetSize.height();
- if (handleOrigin) {
- outputMatrix.preConcat(SkEncodedOriginToMatrix(origin, targetWidth, targetHeight));
- if (SkEncodedOriginSwapsWidthHeight(origin)) {
- std::swap(targetWidth, targetHeight);
- }
- }
-
- if (scale) {
- float scaleX = (float) targetWidth / mDecodeSize.width();
- float scaleY = (float) targetHeight / mDecodeSize.height();
- outputMatrix.preScale(scaleX, scaleY);
- }
-
canvas.setMatrix(outputMatrix);
canvas.drawBitmap(tmp, 0.0f, 0.0f, &paint);
}
diff --git a/libs/hwui/hwui/ImageDecoder.h b/libs/hwui/hwui/ImageDecoder.h
index a08e92478fb0..90261b16e57e 100644
--- a/libs/hwui/hwui/ImageDecoder.h
+++ b/libs/hwui/hwui/ImageDecoder.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include <SkAndroidCodec.h>
#include <SkCodec.h>
#include <SkImageInfo.h>
#include <SkPngChunkReader.h>
@@ -24,17 +25,18 @@
#include <optional>
-class SkAndroidCodec;
-
namespace android {
-class ANDROID_API ImageDecoder {
+class Bitmap;
+
+class ANDROID_API ImageDecoder final {
public:
std::unique_ptr<SkAndroidCodec> mCodec;
sk_sp<SkPngChunkReader> mPeeker;
ImageDecoder(std::unique_ptr<SkAndroidCodec> codec,
sk_sp<SkPngChunkReader> peeker = nullptr);
+ ~ImageDecoder();
bool setTargetSize(int width, int height);
bool setCropRect(const SkIRect*);
@@ -46,25 +48,65 @@ public:
sk_sp<SkColorSpace> getDefaultColorSpace() const;
void setOutColorSpace(sk_sp<SkColorSpace> cs);
- // The size is the final size after scaling and cropping.
+ // The size is the final size after scaling, adjusting for the origin, and
+ // cropping.
SkImageInfo getOutputInfo() const;
int width() const;
int height() const;
+ // True if the current frame is opaque.
bool opaque() const;
bool gray() const;
SkCodec::Result decode(void* pixels, size_t rowBytes);
+ // Return true if the decoder has advanced beyond all frames.
+ bool finished() const;
+
+ bool advanceFrame();
+ bool rewind();
+
+ bool isAnimated();
+ int currentFrame() const;
+
+ SkCodec::FrameInfo getCurrentFrameInfo();
+
private:
+ // State machine for keeping track of how to handle RestorePrevious (RP)
+ // frames in decode().
+ enum class RestoreState {
+ // Neither this frame nor the prior is RP, so there is no need to cache
+ // or restore.
+ kDoNothing,
+
+ // This is the first in a sequence of one or more RP frames. decode()
+ // needs to cache the provided pixels.
+ kFirstRPFrame,
+
+ // This is the second (or later) in a sequence of multiple RP frames.
+ // decode() needs to restore the cached frame that preceded the first RP
+ // frame in the sequence.
+ kRPFrame,
+
+ // This is the first non-RP frame after a sequence of one or more RP
+ // frames. decode() still needs to restore the cached frame. Separate
+ // from kRPFrame because if the following frame is RP the state will
+ // change to kFirstRPFrame.
+ kNeedsRestore,
+ };
+
SkISize mTargetSize;
SkISize mDecodeSize;
SkColorType mOutColorType;
bool mUnpremultipliedRequired;
sk_sp<SkColorSpace> mOutColorSpace;
- int mSampleSize;
+ SkAndroidCodec::AndroidOptions mOptions;
+ bool mCurrentFrameIsIndependent;
+ bool mCurrentFrameIsOpaque;
+ RestoreState mRestoreState;
+ sk_sp<Bitmap> mRestoreFrame;
std::optional<SkIRect> mCropRect;
ImageDecoder(const ImageDecoder&) = delete;
diff --git a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
index 7c1422de0984..f4877f4a4fc4 100644
--- a/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
+++ b/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
@@ -20,8 +20,8 @@
#include <utils/Looper.h>
#endif
-#include <SkBitmap.h>
#include <SkRegion.h>
+#include <SkRuntimeEffect.h>
#include <Rect.h>
#include <RenderNode.h>
@@ -139,6 +139,21 @@ static void android_view_DisplayListCanvas_drawCircleProps(CRITICAL_JNI_PARAMS_C
canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
}
+static void android_view_DisplayListCanvas_drawRippleProps(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr,
+ jlong xPropPtr, jlong yPropPtr,
+ jlong radiusPropPtr, jlong paintPropPtr,
+ jlong progressPropPtr, jlong effectPtr) {
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
+ CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
+ CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
+ CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
+ CanvasPropertyPrimitive* progressProp =
+ reinterpret_cast<CanvasPropertyPrimitive*>(progressPropPtr);
+ SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(effectPtr);
+ canvas->drawRipple(xProp, yProp, radiusProp, paintProp, progressProp, sk_ref_sp(effect));
+}
+
static void android_view_DisplayListCanvas_drawWebViewFunctor(CRITICAL_JNI_PARAMS_COMMA jlong canvasPtr, jint functor) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
canvas->drawWebViewFunctor(functor);
@@ -163,6 +178,7 @@ static JNINativeMethod gMethods[] = {
{ "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
{ "nDrawRoundRect", "(JJJJJJJJ)V",(void*) android_view_DisplayListCanvas_drawRoundRectProps },
{ "nDrawWebViewFunctor", "(JI)V", (void*) android_view_DisplayListCanvas_drawWebViewFunctor },
+ { "nDrawRipple", "(JJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRippleProps },
};
int register_android_view_DisplayListCanvas(JNIEnv* env) {
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index bf19655825b3..3142d927d4c4 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -18,6 +18,7 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
+#include <SkRuntimeEffect.h>
#include <utils/RefBase.h>
#include "CanvasProperty.h"
@@ -54,6 +55,59 @@ private:
sp<uirenderer::CanvasPropertyPaint> mPaint;
};
+class AnimatedRipple : public SkDrawable {
+public:
+ AnimatedRipple(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect)
+ : mX(x)
+ , mY(y)
+ , mRadius(radius)
+ , mPaint(paint)
+ , mProgress(progress)
+ , mRuntimeEffectBuilder(std::move(runtimeEffect)) {}
+
+protected:
+ virtual SkRect onGetBounds() override {
+ const float x = mX->value;
+ const float y = mY->value;
+ const float radius = mRadius->value;
+ return SkRect::MakeLTRB(x - radius, y - radius, x + radius, y + radius);
+ }
+ virtual void onDraw(SkCanvas* canvas) override {
+ SkRuntimeShaderBuilder::BuilderUniform center = mRuntimeEffectBuilder.uniform("in_origin");
+ if (center.fVar != nullptr) {
+ center = SkV2{mX->value, mY->value};
+ }
+
+ SkRuntimeShaderBuilder::BuilderUniform radiusU =
+ mRuntimeEffectBuilder.uniform("in_maxRadius");
+ if (radiusU.fVar != nullptr) {
+ radiusU = mRadius->value;
+ }
+
+ SkRuntimeShaderBuilder::BuilderUniform progressU =
+ mRuntimeEffectBuilder.uniform("in_progress");
+ if (progressU.fVar != nullptr) {
+ progressU = mProgress->value;
+ }
+
+ SkPaint paint = mPaint->value;
+ paint.setShader(mRuntimeEffectBuilder.makeShader(nullptr, false));
+ canvas->drawCircle(mX->value, mY->value, mRadius->value, paint);
+ }
+
+private:
+ sp<uirenderer::CanvasPropertyPrimitive> mX;
+ sp<uirenderer::CanvasPropertyPrimitive> mY;
+ sp<uirenderer::CanvasPropertyPrimitive> mRadius;
+ sp<uirenderer::CanvasPropertyPaint> mPaint;
+ sp<uirenderer::CanvasPropertyPrimitive> mProgress;
+ SkRuntimeShaderBuilder mRuntimeEffectBuilder;
+};
+
class AnimatedCircle : public SkDrawable {
public:
AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index a43627803e71..7faebda8e043 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -85,6 +85,16 @@ void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
}
+void SkiaRecordingCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect) {
+ drawDrawable(mDisplayList->allocateDrawable<AnimatedRipple>(x, y, radius, paint, progress,
+ runtimeEffect));
+}
+
void SkiaRecordingCanvas::enableZ(bool enableZ) {
if (mCurrentBarrier && enableZ) {
// Already in a re-order section, nothing to do
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 83e934974afd..622df43b0528 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -66,6 +66,12 @@ public:
uirenderer::CanvasPropertyPrimitive* y,
uirenderer::CanvasPropertyPrimitive* radius,
uirenderer::CanvasPropertyPaint* paint) override;
+ virtual void drawRipple(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint,
+ uirenderer::CanvasPropertyPrimitive* progress,
+ sk_sp<SkRuntimeEffect> runtimeEffect) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 8ea380a9f3b7..21f8623b1953 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -5019,13 +5019,18 @@ public class ExifInterface {
@Override
public int skipBytes(int byteCount) throws IOException {
- int totalSkip = Math.min(byteCount, mLength - mPosition);
- int skipped = 0;
- while (skipped < totalSkip) {
- skipped += mDataInputStream.skipBytes(totalSkip - skipped);
+ int totalBytesToSkip = Math.min(byteCount, mLength - mPosition);
+ int totalSkipped = 0;
+ while (totalSkipped < totalBytesToSkip) {
+ int skipped = mDataInputStream.skipBytes(totalBytesToSkip - totalSkipped);
+ if (skipped > 0) {
+ totalSkipped += skipped;
+ } else {
+ break;
+ }
}
- mPosition += skipped;
- return skipped;
+ mPosition += totalSkipped;
+ return totalSkipped;
}
public int readUnsignedShort() throws IOException {
diff --git a/media/java/android/media/musicrecognition/OWNERS b/media/java/android/media/musicrecognition/OWNERS
new file mode 100644
index 000000000000..58f5d40dd8c3
--- /dev/null
+++ b/media/java/android/media/musicrecognition/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 830636
+
+joannechung@google.com
+oni@google.com
+volnov@google.com
+
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f22bcd88f8c3..1fd132d00f10 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -547,6 +547,7 @@ public final class MediaSessionManager {
* @param keyEvent the key event to send
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent) {
dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/false, /*needWakeLock=*/false);
}
@@ -558,6 +559,7 @@ public final class MediaSessionManager {
* @param needWakeLock true if a wake lock should be held while sending the key
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) {
dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/false, needWakeLock);
}
@@ -630,6 +632,7 @@ public final class MediaSessionManager {
* @param musicOnly true if key event should only be sent to music stream
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int streamType,
boolean musicOnly) {
dispatchVolumeKeyEventInternal(keyEvent, streamType, musicOnly, /*asSystemService=*/false);
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
index 67d6e9d266c8..e96cae6ba1bc 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendInfo.java
@@ -46,6 +46,10 @@ public class FrontendInfo {
FrontendCapabilities frontendCap) {
mId = id;
mType = type;
+ // if max Frequency is negative, we set it as max value of the Integer.
+ if (maxFrequency < 0) {
+ maxFrequency = Integer.MAX_VALUE;
+ }
mFrequencyRange = new Range<>(minFrequency, maxFrequency);
mSymbolRateRange = new Range<>(minSymbolRate, maxSymbolRate);
mAcquireRange = acquireRange;
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 4aeebe47f1ae..0f6190722aa3 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -61,6 +61,37 @@ int ResultToErrorCode(SkCodec::Result result) {
}
}
+const char* AImageDecoder_resultToString(int result) {
+ switch (result) {
+ case ANDROID_IMAGE_DECODER_SUCCESS:
+ return "ANDROID_IMAGE_DECODER_SUCCESS";
+ case ANDROID_IMAGE_DECODER_INCOMPLETE:
+ return "ANDROID_IMAGE_DECODER_INCOMPLETE";
+ case ANDROID_IMAGE_DECODER_ERROR:
+ return "ANDROID_IMAGE_DECODER_ERROR";
+ case ANDROID_IMAGE_DECODER_INVALID_CONVERSION:
+ return "ANDROID_IMAGE_DECODER_INVALID_CONVERSION";
+ case ANDROID_IMAGE_DECODER_INVALID_SCALE:
+ return "ANDROID_IMAGE_DECODER_INVALID_SCALE";
+ case ANDROID_IMAGE_DECODER_BAD_PARAMETER:
+ return "ANDROID_IMAGE_DECODER_BAD_PARAMETER";
+ case ANDROID_IMAGE_DECODER_INVALID_INPUT:
+ return "ANDROID_IMAGE_DECODER_INVALID_INPUT";
+ case ANDROID_IMAGE_DECODER_SEEK_ERROR:
+ return "ANDROID_IMAGE_DECODER_SEEK_ERROR";
+ case ANDROID_IMAGE_DECODER_INTERNAL_ERROR:
+ return "ANDROID_IMAGE_DECODER_INTERNAL_ERROR";
+ case ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT:
+ return "ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT";
+ case ANDROID_IMAGE_DECODER_FINISHED:
+ return "ANDROID_IMAGE_DECODER_FINISHED";
+ case ANDROID_IMAGE_DECODER_INVALID_STATE:
+ return "ANDROID_IMAGE_DECODER_INVALID_STATE";
+ default:
+ return nullptr;
+ }
+}
+
static int createFromStream(std::unique_ptr<SkStreamRewindable> stream, AImageDecoder** outDecoder) {
SkCodec::Result result;
auto codec = SkCodec::MakeFromStream(std::move(stream), &result, nullptr,
@@ -173,7 +204,13 @@ int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* decoder, int32_t format)
|| format > ANDROID_BITMAP_FORMAT_RGBA_F16) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
- return toDecoder(decoder)->setOutColorType(getColorType((AndroidBitmapFormat) format))
+
+ auto* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->currentFrame() != 0) {
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
+ return imageDecoder->setOutColorType(getColorType((AndroidBitmapFormat) format))
? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
}
@@ -185,6 +222,10 @@ int AImageDecoder_setDataSpace(AImageDecoder* decoder, int32_t dataspace) {
}
ImageDecoder* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->currentFrame() != 0) {
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
imageDecoder->setOutColorSpace(std::move(cs));
return ANDROID_IMAGE_DECODER_SUCCESS;
}
@@ -279,7 +320,12 @@ int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* decoder, bool requir
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
- return toDecoder(decoder)->setUnpremultipliedRequired(required)
+ auto* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->currentFrame() != 0) {
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
+ return imageDecoder->setUnpremultipliedRequired(required)
? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_CONVERSION;
}
@@ -288,7 +334,12 @@ int AImageDecoder_setTargetSize(AImageDecoder* decoder, int32_t width, int32_t h
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
- return toDecoder(decoder)->setTargetSize(width, height)
+ auto* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->currentFrame() != 0) {
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
+ return imageDecoder->setTargetSize(width, height)
? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_INVALID_SCALE;
}
@@ -309,10 +360,15 @@ int AImageDecoder_setCrop(AImageDecoder* decoder, ARect crop) {
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
+ auto* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->currentFrame() != 0) {
+ return ANDROID_IMAGE_DECODER_INVALID_STATE;
+ }
+
SkIRect cropIRect;
cropIRect.setLTRB(crop.left, crop.top, crop.right, crop.bottom);
SkIRect* cropPtr = cropIRect == SkIRect::MakeEmpty() ? nullptr : &cropIRect;
- return toDecoder(decoder)->setCropRect(cropPtr)
+ return imageDecoder->setCropRect(cropPtr)
? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
@@ -341,6 +397,10 @@ int AImageDecoder_decodeImage(AImageDecoder* decoder,
return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
}
+ if (imageDecoder->finished()) {
+ return ANDROID_IMAGE_DECODER_FINISHED;
+ }
+
return ResultToErrorCode(imageDecoder->decode(pixels, stride));
}
@@ -352,7 +412,7 @@ bool AImageDecoder_isAnimated(AImageDecoder* decoder) {
if (!decoder) return false;
ImageDecoder* imageDecoder = toDecoder(decoder);
- return imageDecoder->mCodec->codec()->getFrameCount() > 1;
+ return imageDecoder->isAnimated();
}
int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
@@ -369,3 +429,109 @@ int32_t AImageDecoder_getRepeatCount(AImageDecoder* decoder) {
}
return count;
}
+
+int AImageDecoder_advanceFrame(AImageDecoder* decoder) {
+ if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ if (!imageDecoder->isAnimated()) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ if (imageDecoder->advanceFrame()) {
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+ }
+
+ if (imageDecoder->finished()) {
+ return ANDROID_IMAGE_DECODER_FINISHED;
+ }
+
+ return ANDROID_IMAGE_DECODER_INCOMPLETE;
+}
+
+int AImageDecoder_rewind(AImageDecoder* decoder) {
+ if (!decoder) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ ImageDecoder* imageDecoder = toDecoder(decoder);
+ if (!imageDecoder->isAnimated()) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ return imageDecoder->rewind() ? ANDROID_IMAGE_DECODER_SUCCESS
+ : ANDROID_IMAGE_DECODER_SEEK_ERROR;
+}
+
+AImageDecoderFrameInfo* AImageDecoderFrameInfo_create() {
+ return reinterpret_cast<AImageDecoderFrameInfo*>(new SkCodec::FrameInfo);
+}
+
+static SkCodec::FrameInfo* toFrameInfo(AImageDecoderFrameInfo* info) {
+ return reinterpret_cast<SkCodec::FrameInfo*>(info);
+}
+
+static const SkCodec::FrameInfo* toFrameInfo(const AImageDecoderFrameInfo* info) {
+ return reinterpret_cast<const SkCodec::FrameInfo*>(info);
+}
+
+void AImageDecoderFrameInfo_delete(AImageDecoderFrameInfo* info) {
+ delete toFrameInfo(info);
+}
+
+int AImageDecoder_getFrameInfo(AImageDecoder* decoder,
+ AImageDecoderFrameInfo* info) {
+ if (!decoder || !info) {
+ return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+ }
+
+ auto* imageDecoder = toDecoder(decoder);
+ if (imageDecoder->finished()) {
+ return ANDROID_IMAGE_DECODER_FINISHED;
+ }
+
+ *toFrameInfo(info) = imageDecoder->getCurrentFrameInfo();
+ return ANDROID_IMAGE_DECODER_SUCCESS;
+}
+
+int64_t AImageDecoderFrameInfo_getDuration(const AImageDecoderFrameInfo* info) {
+ if (!info) return 0;
+
+ return toFrameInfo(info)->fDuration * 1'000'000;
+}
+
+ARect AImageDecoderFrameInfo_getFrameRect(const AImageDecoderFrameInfo* info) {
+ if (!info) {
+ return { 0, 0, 0, 0};
+ }
+
+ const SkIRect& r = toFrameInfo(info)->fFrameRect;
+ return { r.left(), r.top(), r.right(), r.bottom() };
+}
+
+bool AImageDecoderFrameInfo_hasAlphaWithinBounds(const AImageDecoderFrameInfo* info) {
+ if (!info) return false;
+
+ return toFrameInfo(info)->fHasAlphaWithinBounds;
+}
+
+int32_t AImageDecoderFrameInfo_getDisposeOp(const AImageDecoderFrameInfo* info) {
+ if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kKeep)
+ == ANDROID_IMAGE_DECODER_DISPOSE_OP_NONE);
+ static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestoreBGColor)
+ == ANDROID_IMAGE_DECODER_DISPOSE_OP_BACKGROUND);
+ static_assert(static_cast<int>(SkCodecAnimation::DisposalMethod::kRestorePrevious)
+ == ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS);
+ return static_cast<int>(toFrameInfo(info)->fDisposalMethod);
+}
+
+int32_t AImageDecoderFrameInfo_getBlendOp(const AImageDecoderFrameInfo* info) {
+ if (!info) return ANDROID_IMAGE_DECODER_BAD_PARAMETER;
+
+ switch (toFrameInfo(info)->fBlend) {
+ case SkCodecAnimation::Blend::kSrc:
+ return ANDROID_IMAGE_DECODER_BLEND_OP_SRC;
+ case SkCodecAnimation::Blend::kSrcOver:
+ return ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER;
+ }
+}
diff --git a/native/graphics/jni/libjnigraphics.map.txt b/native/graphics/jni/libjnigraphics.map.txt
index a184ab9d42e9..d8c3cefd30ca 100644
--- a/native/graphics/jni/libjnigraphics.map.txt
+++ b/native/graphics/jni/libjnigraphics.map.txt
@@ -1,5 +1,6 @@
LIBJNIGRAPHICS {
global:
+ AImageDecoder_resultToString; # introduced=31
AImageDecoder_createFromAAsset; # introduced=30
AImageDecoder_createFromFd; # introduced=30
AImageDecoder_createFromBuffer; # introduced=30
@@ -15,12 +16,22 @@ LIBJNIGRAPHICS {
AImageDecoder_setCrop; # introduced=30
AImageDecoder_isAnimated; # introduced=31
AImageDecoder_getRepeatCount; # introduced=31
+ AImageDecoder_advanceFrame; # introduced=31
+ AImageDecoder_rewind; # introduced=31
+ AImageDecoder_getFrameInfo; # introduced = 31
AImageDecoderHeaderInfo_getWidth; # introduced=30
AImageDecoderHeaderInfo_getHeight; # introduced=30
AImageDecoderHeaderInfo_getMimeType; # introduced=30
AImageDecoderHeaderInfo_getAlphaFlags; # introduced=30
AImageDecoderHeaderInfo_getAndroidBitmapFormat; # introduced=30
AImageDecoderHeaderInfo_getDataSpace; # introduced=30
+ AImageDecoderFrameInfo_create; # introduced = 31
+ AImageDecoderFrameInfo_delete; # introduced = 31
+ AImageDecoderFrameInfo_getDuration; # introduced = 31
+ AImageDecoderFrameInfo_getFrameRect; # introduced = 31
+ AImageDecoderFrameInfo_hasAlphaWithinBounds; # introduced = 31
+ AImageDecoderFrameInfo_getDisposeOp; # introduced = 31
+ AImageDecoderFrameInfo_getBlendOp; # introduced = 31
AndroidBitmap_getInfo;
AndroidBitmap_getDataSpace;
AndroidBitmap_lockPixels;
diff --git a/native/webview/TEST_MAPPING b/native/webview/TEST_MAPPING
new file mode 100644
index 000000000000..bd25200ffc38
--- /dev/null
+++ b/native/webview/TEST_MAPPING
@@ -0,0 +1,36 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWebkitTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsHostsideWebViewTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "GtsWebViewTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.test.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "GtsWebViewHostTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.test.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 1f3ee6d27685..b0c316908a10 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -347,17 +347,19 @@ public class PackageInstallerActivity extends AlertActivity {
if (!wasSetUp) {
return;
}
-
- // load dummy layout with OK button disabled until we override this layout in
- // startInstallConfirm
- bindUi();
- checkIfAllowedAndInitiateInstall();
}
@Override
protected void onResume() {
super.onResume();
+ if (mAppSnippet != null) {
+ // load dummy layout with OK button disabled until we override this layout in
+ // startInstallConfirm
+ bindUi();
+ checkIfAllowedAndInitiateInstall();
+ }
+
if (mOk != null) {
mOk.setEnabled(mEnableOk);
}
diff --git a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
index 1c0e718a17b2..4d454941af7c 100644
--- a/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
+++ b/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java
@@ -19,9 +19,11 @@ package com.android.settingslib.emergencynumber;
import static android.telephony.emergency.EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE;
import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.provider.Settings;
+import android.net.Uri;
+import android.os.Bundle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
@@ -40,7 +42,16 @@ import java.util.Map;
*/
public class EmergencyNumberUtils {
private static final String TAG = "EmergencyNumberUtils";
- private static final String EMERGENCY_GESTURE_CALL_NUMBER = "emergency_gesture_call_number";
+
+ public static final Uri EMERGENCY_NUMBER_OVERRIDE_AUTHORITY = new Uri.Builder().scheme(
+ ContentResolver.SCHEME_CONTENT)
+ .authority("com.android.emergency.numbers")
+ .build();
+ public static final String METHOD_NAME_GET_EMERGENCY_NUMBER_OVERRIDE =
+ "GET_EMERGENCY_NUMBER_OVERRIDE";
+ public static final String METHOD_NAME_SET_EMERGENCY_NUMBER_OVERRIDE =
+ "SET_EMERGENCY_NUMBER_OVERRIDE";
+ public static final String EMERGENCY_GESTURE_CALL_NUMBER = "emergency_gesture_call_number";
@VisibleForTesting
static final String FALL_BACK_NUMBER = "112";
@@ -77,12 +88,28 @@ public class EmergencyNumberUtils {
* #getDefaultPoliceNumber()}).
*/
public String getPoliceNumber() {
- final String userProvidedNumber = Settings.Secure.getString(mContext.getContentResolver(),
- EMERGENCY_GESTURE_CALL_NUMBER);
+ final String userProvidedNumber = getEmergencyNumberOverride();
return TextUtils.isEmpty(userProvidedNumber)
? getDefaultPoliceNumber() : userProvidedNumber;
}
+ /**
+ * Sets device-local emergency number override
+ */
+ public void setEmergencyNumberOverride(String number) {
+ final Bundle bundle = new Bundle();
+ bundle.putString(EMERGENCY_GESTURE_CALL_NUMBER, number);
+ mContext.getContentResolver().call(EMERGENCY_NUMBER_OVERRIDE_AUTHORITY,
+ METHOD_NAME_SET_EMERGENCY_NUMBER_OVERRIDE, null /* args */, bundle);
+ }
+
+ private String getEmergencyNumberOverride() {
+ final Bundle bundle = mContext.getContentResolver().call(
+ EMERGENCY_NUMBER_OVERRIDE_AUTHORITY,
+ METHOD_NAME_GET_EMERGENCY_NUMBER_OVERRIDE, null /* args */, null /* bundle */);
+ return bundle == null ? null : bundle.getString(EMERGENCY_GESTURE_CALL_NUMBER);
+ }
+
private List<EmergencyNumber> getPromotedEmergencyNumbers(int categories) {
// TODO(b/171542607): Use platform API when its bug is fixed.
Map<Integer, List<EmergencyNumber>> allLists = filterEmergencyNumbersByCategories(
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index c2b26bce6e1a..d76a8a177449 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skep tans nuwe gebruiker …"</string>
<string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 65ce6e0200f4..85b5bc2a574e 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"አዲስ ተጠቃሚ በመፍጠር ላይ…"</string>
<string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 3ea96c7dbf25..f2605597c803 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> إلى أن يتم شحن الجهاز بالكامل"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - التحسين لسلامة البطارية"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - التحسين للحفاظ على سلامة البطارية"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
@@ -557,7 +557,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"جارٍ إنشاء مستخدم جديد…"</string>
<string name="user_nickname" msgid="262624187455825083">"اللقب"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"إضافة ضيف"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"إزالة جلسة الضيف"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ضيف"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"التقاط صورة"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"اختيار صورة"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index a2596878e33f..32be72d32a12 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰি থকা হৈছে…"</string>
<string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"অতিথিৰ ছেশ্বন সমাপ্ত কৰক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 2cbd681cef45..88e99ce3c9fb 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni istifadəçi yaradılır…"</string>
<string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 4d8e348cb746..4a820ea520d8 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Napuniće se za <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – napuniće se za <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimizuje se radi stanja baterije"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimizuje se radi boljeg stanja baterije"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Pravi se novi korisnik…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 4d6f3ac6a634..6a16246de0a3 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ствараецца новы карыстальнік…"</string>
<string name="user_nickname" msgid="262624187455825083">"Псеўданім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Дадаць госця"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Выдаліць госця"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Госць"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зрабіць фота"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбраць відарыс"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ef0412b1485d..07ba66a59e92 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до пълно зареждане"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оптимизиране за състоян. на батерията"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оптимизиране с цел състоянието на батерията"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Създава се нов потребител…"</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Прекратяване на сесията като гост"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 5b95399e83b8..99ee1d646346 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"নতুন ব্যবহারকারী তৈরি করা হচ্ছে…"</string>
<string name="user_nickname" msgid="262624187455825083">"বিশেষ নাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ করুন"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি সরান"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ফটো তুলুন"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"একটি ইমেজ বেছে নিন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 00d8087e5483..eedad341189e 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kreiranje novog korisnika…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 98d502d050eb..209b2d601933 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g>: optimitzant per a l\'estat de la bateria"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està optimitzant per preservar l\'estat de la bateria"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"S\'està creant l\'usuari…"</string>
<string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a9a5f483eaa3..b3141e405860 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytváření nového uživatele…"</string>
<string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 738ed3c697a8..a7fa91f34dda 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Opretter ny bruger…"</string>
<string name="user_nickname" msgid="262624187455825083">"Kaldenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tilføj gæsten"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gæsten"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gæst"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tag et billede"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vælg et billede"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index e274d639b33c..361b932cea48 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Neuer Nutzer wird erstellt…"</string>
<string name="user_nickname" msgid="262624187455825083">"Alias"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast hinzufügen"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Gast entfernen"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto machen"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Bild auswählen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 66244eb3b0f6..a3b3d26c92c5 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για ολοκλήρωση της φόρτισης"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> για την ολοκλήρωση της φόρτισης"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Βελτιστοποίηση κατάστασης μπαταρίας"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Βελτιστοποίηση για τη διατήρηση της καλής κατάστασης της μπαταρίας"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Δημιουργία νέου χρήστη…"</string>
<string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index f5a0e2c1fb9b..fe7515f68954 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"End Guest session"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 6f11e804e893..75a66781131b 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"End Guest session"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index f5a0e2c1fb9b..fe7515f68954 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"End Guest session"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index f5a0e2c1fb9b..fe7515f68954 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creating new user…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Add guest"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remove guest"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"End Guest session"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Guest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Take a photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choose an image"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index bfca10955c4b..aed0800ba197 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎Creating new user…‎‏‎‎‏‎"</string>
<string name="user_nickname" msgid="262624187455825083">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎Nickname‎‏‎‎‏‎"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎Add guest‎‏‎‎‏‎"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‎‎Remove guest‎‏‎‎‏‎"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎End guest session‎‏‎‎‏‎"</string>
<string name="guest_nickname" msgid="6332276931583337261">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎Guest‎‏‎‎‏‎"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‎Take a photo‎‏‎‎‏‎"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‎Choose an image‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 44ae8c2e6545..f9260a8745af 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario nuevo…"</string>
<string name="user_nickname" msgid="262624187455825083">"Sobrenombre"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Agregar invitado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Finalizar sesión de invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tomar una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Elegir una imagen"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 236394c5e641..bc176234e09b 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario…"</string>
<string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Finalizar sesión de invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index c8fd94f72849..c73f1365c8c3 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Uue kasutaja loomine …"</string>
<string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 226ffba24621..2f51ac03ed77 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Optimizatzen bateria egoera onean mantentzeko"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Optimizatzen, bateria egoera onean mantentzeko"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Beste erabiltzaile bat sortzen…"</string>
<string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Amaitu gonbidatuentzako saioa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 917a637f1e01..038b81503c89 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"درحال ایجاد کاربر جدید…"</string>
<string name="user_nickname" msgid="262624187455825083">"نام مستعار"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"افزودن مهمان"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"حذف مهمان"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"مهمان"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"عکس گرفتن"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"انتخاب تصویر"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index b1038025bf1e..33b6142194dd 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Luodaan uutta käyttäjää…"</string>
<string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 91d14d40e269..01492c2f9719 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la charge complète"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> : <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimisation pour la santé de la pile"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimisation pour préserver la pile"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Créer un utilisateur…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Mettre fin à la session d\'invité"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Sélectionner une image"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 2518fe10d06e..04ed5fee3bde 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Création d\'un nouvel utilisateur…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ajouter un invité"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Supprimer l\'invité"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Invité"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Prendre une photo"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Choisir une image"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 486afe346ac2..b59395cf89e9 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> para completar a carga"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g>: optimizando para manter a batería en bo estado"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g>: optimizando a preservación da batería"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creando usuario novo…"</string>
<string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 2bebe36818c5..601ffde9d50e 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"નવા વપરાશકર્તા બનાવી રહ્યાં છીએ…"</string>
<string name="user_nickname" msgid="262624187455825083">"ઉપનામ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"અતિથિ ઉમેરો"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"અતિથિને કાઢી નાખો"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"અતિથિ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ફોટો લો"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"છબી પસંદ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 824ab25a5bcc..974d00cd10f8 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नया उपयोगकर्ता बनाया जा रहा है…"</string>
<string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"मेहमान के तौर पर ब्राउज़ करने का सेशन खत्म करें"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index cd21a5fe1da5..f7924285f9ee 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Izrada novog korisnika…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c3b859cb0724..2bf5325b24ff 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Új felhasználó létrehozása…"</string>
<string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 041ad0e191d5..fea1e128d216 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լիցքավորումը"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լիցքավորումը"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Օպտիմալացվում է"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Օպտիմալացվում է մարտկոցի պահպանման համար"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ստեղծվում է օգտատիրոջ նոր պրոֆիլ…"</string>
<string name="user_nickname" msgid="262624187455825083">"Կեղծանուն"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Ավելացնել հյուր"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Հեռացնել հյուրին"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Ավարտել հյուրի աշխատաշրջանը"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Հյուր"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Լուսանկարել"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Ընտրել պատկեր"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 332d5b35e857..7298cea4e00d 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Membuat pengguna baru …"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambahkan tamu"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Hapus tamu"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Tamu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih gambar"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index f40136452674..bf6c03167476 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Stofnar nýjan notanda…"</string>
<string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index ef5e2ff912ad..2ed92e4be0b8 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Creazione nuovo utente…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index db2ffe5d2f17..bf4c35e000ef 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"בתהליך יצירה של משתמש חדש…"</string>
<string name="user_nickname" msgid="262624187455825083">"כינוי"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"הוספת אורח"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"הסרת אורח"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"אורח"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"צילום תמונה"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"לבחירת תמונה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 9e9db3d2be38..f467c6049722 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"新しいユーザーを作成しています…"</string>
<string name="user_nickname" msgid="262624187455825083">"ニックネーム"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ゲストを追加"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ゲストを削除"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"ゲスト セッションを終了する"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ゲスト"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"写真を撮る"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"画像を選択"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index ec3900883140..493839f0a07f 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"მიმდინარეობს ახალი მომხმარებლის შექმნა…"</string>
<string name="user_nickname" msgid="262624187455825083">"მეტსახელი"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"სტუმრის დამატება"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"სტუმრის ამოშლა"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"სტუმარი"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ფოტოს გადაღება"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"აირჩიეთ სურათი"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 881a13cf1cba..83d859b83255 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяның жұмыс істеу қабілеті оңтайландырылуда"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарея жұмысын оңтайландыру"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңа пайдаланушы профилі жасалуда…"</string>
<string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақты енгізу"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты өшіру"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 14f77889d83d..db571d6f2dfe 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"កំពុងបង្កើត​អ្នកប្រើប្រាស់ថ្មី…"</string>
<string name="user_nickname" msgid="262624187455825083">"ឈ្មោះ​ហៅក្រៅ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូល​ភ្ញៀវ"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"លុប​​​ភ្ញៀវ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើស​រូបភាព"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index a279d22538a1..2e8b9f1438d9 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಇದೆ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜ್ ಆಗಲು <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯ ಬೇಕು"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿಯ ಆರೋಗ್ಯಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿಯ ಸುಸ್ಥಿತಿಗಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index de694884466b..0294e9d4d8c3 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"새로운 사용자를 만드는 중…"</string>
<string name="user_nickname" msgid="262624187455825083">"닉네임"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"게스트 추가"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"게스트 삭제"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"게스트"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"사진 찍기"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"이미지 선택"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index e70460ffa06d..0c73cf67c517 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Жаңы колдонуучу түзүлүүдө…"</string>
<string name="user_nickname" msgid="262624187455825083">"Ылакап аты"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Конок кошуу"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Конокту өчүрүү"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Конок"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сүрөткө тартуу"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сүрөт тандаңыз"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index c63cec8fc7a2..fbe814ab619b 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ກຳລັງສ້າງຜູ້ໃຊ້ໃໝ່…"</string>
<string name="user_nickname" msgid="262624187455825083">"ຊື່ຫຼິ້ນ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ເພີ່ມແຂກ"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ລຶບແຂກອອກ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ແຂກ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ຖ່າຍຮູບ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ເລືອກຮູບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index d040edf25b3b..b3d8e171d22e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Kuriamas naujas naudotojas…"</string>
<string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 74c0dd5ccad6..3c69e642156a 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Notiek jauna lietotāja izveide…"</string>
<string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 739bceb81e1a..b909359faf3b 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Се создава нов корисник…"</string>
<string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај гостин"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index b7de4293bc1f..8f83ee103de3 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കുന്നു…"</string>
<string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c7a2edd7c3fb..8168b7922e63 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Цэнэглэх хүртэл үлдсэн <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - цэнэглэх хүртэл <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейн чанарыг оновчилж байна"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейн барилтыг оновчилж байна"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Шинэ хэрэглэгч үүсгэж байна…"</string>
<string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Зочны сургалтыг дуусгах"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index d29cb590da81..f47d8e005508 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नवीन वापरकर्ता तयार करत आहे…"</string>
<string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index c593e4b8f9d9..fb2826f9609c 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Mencipta pengguna baharu…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nama panggilan"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Tambah tetamu"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Alih keluar tetamu"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Tamatkan sesi tetamu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Tetamu"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ambil foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pilih imej"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index aa9d3d63fb6c..d98d4429b314 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"အသုံးပြုသူအသစ် ပြုလုပ်နေသည်…"</string>
<string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 9494c398a93b..944c48ebdde2 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> til batteriet er fulladet"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> til batteriet er fulladet"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimaliserer batteritilstanden"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – optimaliserer batteritilstanden"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Oppretter en ny bruker …"</string>
<string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index e31fb4eff9b1..9a0d2eda8626 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"नयाँ प्रयोगकर्ता बनाउँदै…"</string>
<string name="user_nickname" msgid="262624187455825083">"उपनाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथि थप्नुहोस्"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"अतिथि हटाउनुहोस्"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"अतिथि"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो खिच्नुहोस्"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कुनै फोटो छनौट गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 0b75fdd16a29..a8e4fb5b2d26 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Nieuwe gebruiker maken…"</string>
<string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Gastsessie beëindigen"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index cfde61f86677..306ef440a02c 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରାଯାଉଛି…"</string>
<string name="user_nickname" msgid="262624187455825083">"ଡାକନାମ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ଅତିଥି ଯୋଗ କରନ୍ତୁ"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ଅତିଥିଙ୍କୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ଅତିଥି"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ଗୋଟିଏ ଫଟୋ ଉଠାନ୍ତୁ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ଏକ ଛବି ବାଛନ୍ତୁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 122186256a1e..e231a26671e6 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ਤੱਕ ਚਾਰਜ ਹੋ ਜਾਵੇਗੀ"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਸਥਿਤੀ ਲਈ ਅਨੁਕੂਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਦੀ ਸਥਿਤੀ ਲਈ ਅਨੁਕੂਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ…"</string>
<string name="user_nickname" msgid="262624187455825083">"ਉਪਨਾਮ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ਮਹਿਮਾਨ ਸ਼ਾਮਲ ਕਰੋ"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"ਮਹਿਮਾਨ ਹਟਾਓ"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"ਮਹਿਮਾਨ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ਇੱਕ ਫ਼ੋਟੋ ਖਿੱਚੋ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ਕੋਈ ਚਿੱਤਰ ਚੁਣੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 102835c9bd97..a62e9cc440e1 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Do naładowania <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – do naładowania <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optymalizuję, by utrzymać baterię w dobrym stanie"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optymalizuję, aby utrzymać baterię w dobrym stanie"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Tworzę nowego użytkownika…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 99019a683d96..fe922c0926ec 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 238e54bb5fd3..5d1f88049160 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"A criar novo utilizador…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudónimo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 99019a683d96..fe922c0926ec 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Criando novo usuário…"</string>
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index df95dbc76ad4..765f83a59a3a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Se creează un utilizator nou…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 68826d7552fc..98b320394c0a 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Создаем нового пользователя…"</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить аккаунт гостя"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 736445da0910..087f140362b7 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ආරෝපණය වන තෙක් <xliff:g id="TIME">%1$s</xliff:g> ඇත"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය වන තෙක් <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරි සෞඛ්‍යය සඳහා ප්‍රශස්ත කරමින්"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරි ආයු කාලය වැඩි දියුණු කරමින්"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"නව පරිශීලක තනමින්…"</string>
<string name="user_nickname" msgid="262624187455825083">"අපනාමය"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"අමුත්තා එක් කරන්න"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"අමුත්තා ඉවත් කරන්න"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"අමුත්තා"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ඡායාරූපයක් ගන්න"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"රූපයක් තෝරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 265ec8fcff04..858f01758a86 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Vytvára sa nový používateľ…"</string>
<string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 2e6fc0ecdfe1..2386b13873e8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Še <xliff:g id="TIME">%1$s</xliff:g> do polne napolnjenosti"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do polne napolnjenosti"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimizacija za ohran. zmog. baterije"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Optimizacija za ohranjanje zmogljivosti baterije"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Ustvarjanje novega uporabnika …"</string>
<string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 821e897b6417..8d53b256f874 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Po krijohet një përdorues i ri…"</string>
<string name="user_nickname" msgid="262624187455825083">"Pseudonimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Shto të ftuar"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Hiq të ftuarin"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Jepi fund sesionit të vizitorit"</string>
<string name="guest_nickname" msgid="6332276931583337261">"I ftuar"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Bëj një fotografi"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Zgjidh një imazh"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 207ca7437e5a..0b64a705cd7d 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"Напуниће се за <xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – напуниће се за <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оптимизује се ради стања батерије"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оптимизује се ради бољег стања батерије"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
@@ -554,7 +554,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Прави се нови корисник…"</string>
<string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7afd34464620..58eda86276e3 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Skapar ny användare …"</string>
<string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index b08da895c4b1..889163bcbd40 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -492,8 +492,8 @@
<string name="status_unavailable" msgid="5279036186589861608">"Hamna"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"Imechagua anwani ya MAC kwa nasibu"</string>
<plurals name="wifi_tether_connected_summary" formatted="false" msgid="6317236306047306139">
- <item quantity="other">Imeunganisha vifaa %1$d</item>
- <item quantity="one">Imeunganisha kifaa %1$d</item>
+ <item quantity="other">Vifaa %1$d vimeunganishwa</item>
+ <item quantity="one">Kifaa %1$d kimeunganishwa</item>
</plurals>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"Muda zaidi."</string>
<string name="accessibility_manual_zen_less_time" msgid="6828877595848229965">"Muda kidogo."</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Inaweka mtumiaji mpya…"</string>
<string name="user_nickname" msgid="262624187455825083">"Jina wakilishi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Weka mgeni"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Ondoa mgeni"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Mgeni"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Piga picha"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chagua picha"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 5fdf8bd61308..e0de7782f5b2 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"புதிய பயனரை உருவாக்குகிறது…"</string>
<string name="user_nickname" msgid="262624187455825083">"புனைப்பெயர்"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"கெஸ்ட்டைச் சேர்"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"கெஸ்ட்டை அகற்று"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"கெஸ்ட்"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"படமெடுங்கள்"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"படத்தைத் தேர்வுசெய்யுங்கள்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 38f08b2b8603..53f4abf90079 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%1$s</xliff:g> సమయం మిగిలి ఉంది"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జ్ అవ్వడానికి <xliff:g id="TIME">%2$s</xliff:g> పడుతుంది"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - బ్యాటరీ స్థితిని ఆప్టిమైజ్ చేయడం కోసం"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - బ్యాటరీ జీవితకాలాన్ని పెంచడం కోసం ఆప్టిమైజ్ చేస్తోంది"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"కొత్త యూజర్‌ను క్రియేట్ చేస్తోంది…"</string>
<string name="user_nickname" msgid="262624187455825083">"మారుపేరు"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"అతిథిని జోడించండి"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"అతిథిని తీసివేయండి"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"అతిథి"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ఒక ఫోటో తీయండి"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ఇమేజ్‌ను ఎంచుకోండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index a8951388e488..5f93563229fa 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -284,7 +284,7 @@
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"เพิ่มระดับการบันทึก Wi‑Fi แสดงต่อ SSID RSSI ในตัวเลือก Wi‑Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"ลดการเปลืองแบตเตอรี่และเพิ่มประสิทธิภาพเครือข่าย"</string>
<string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"เมื่อเปิดใช้โหมดนี้ ที่อยู่ MAC ของอุปกรณ์นี้อาจเปลี่ยนทุกครั้งที่เชื่อมต่อกับเครือข่ายที่มีการเปิดใช้การสุ่ม MAC"</string>
- <string name="wifi_metered_label" msgid="8737187690304098638">"แบบจำกัดปริมาณอินเทอร์เน็ต"</string>
+ <string name="wifi_metered_label" msgid="8737187690304098638">"แบบจำกัดปริมาณ"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"ไม่มีการวัดปริมาณอินเทอร์เน็ต"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"ขนาดบัฟเฟอร์ของตัวบันทึก"</string>
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"เลือกขนาด Logger ต่อบัฟเฟอร์ไฟล์บันทึก"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"กำลังสร้างผู้ใช้ใหม่…"</string>
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้เข้าร่วม"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้เข้าร่วมออก"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"จบเซสชันผู้เยี่ยมชม"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index b451d894d254..9bbfb1d82f68 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Gumagawa ng bagong user…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Tapusin ang session ng bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e1ff56baf17d..9dd32b6f78ea 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yeni kullanıcı oluşturuluyor…"</string>
<string name="user_nickname" msgid="262624187455825083">"Takma ad"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Misafir ekle"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Misafir oturumunu kaldır"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Misafir oturumunu sonlandır"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Misafir"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotoğraf çek"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Resim seç"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 6806ce6f1f4a..99cc95871346 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – стан акумулятора оптимізується"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оптимізація для збереження заряду акумулятора"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
@@ -555,7 +555,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Створення нового користувача…"</string>
<string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 5a8b6dc87006..515cf702cdea 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"نیا صارف تخلیق کرنا…"</string>
<string name="user_nickname" msgid="262624187455825083">"عرفی نام"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"مہمان کو شامل کریں"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"مہمان کو ہٹائیں"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"مہمان"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ایک تصویر لیں"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ایک تصویر منتخب کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 7530016763b0..18300468023c 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g> ichida toʻladi"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> ichida toʻladi"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batareya quvvati muvozanatlanmoqda"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> – Batareya uchun optimizatsiya"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Yangi foydalanuvchi yaratilmoqda…"</string>
<string name="user_nickname" msgid="262624187455825083">"Nik"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Mehmon rejimini olib tashlash"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Mehmon seansini yakunlash"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 643fdb9f7ab6..2d56e45aabf6 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Đang tạo người dùng mới…"</string>
<string name="user_nickname" msgid="262624187455825083">"Biệt hiệu"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Thêm khách"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Xóa phiên khách"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"Kết thúc phiên khách"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Khách"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Chụp ảnh"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Chọn một hình ảnh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 81d8106b484e..6b64d2717266 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在创建新用户…"</string>
<string name="user_nickname" msgid="262624187455825083">"昵称"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"添加访客"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"移除访客"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"访客"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍摄照片"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"选择图片"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 39a12aa23bbd..4ab580e01f28 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"還需 <xliff:g id="TIME">%1$s</xliff:g>才能充滿電"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - 還需 <xliff:g id="TIME">%2$s</xliff:g>才能充滿電"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在優化電池狀態"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - 優化電池效能"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充電"</string>
@@ -553,7 +553,7 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
<string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
+ <string name="guest_exit_guest" msgid="4754204715192830850">"結束訪客工作階段"</string>
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index cc35ed302960..46695dbc88ba 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -450,7 +450,7 @@
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
<string name="power_remaining_charging_duration_only" msgid="7415639699283965818">"<xliff:g id="TIME">%1$s</xliff:g>後充飽電"</string>
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽電"</string>
- <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - 針對電池狀態進行最佳化調整"</string>
+ <string name="power_charging_limited" msgid="1956874810658999681">"<xliff:g id="LEVEL">%1$s</xliff:g> - 最佳化調整電池狀態"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
<string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"正在建立新使用者…"</string>
<string name="user_nickname" msgid="262624187455825083">"暱稱"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"新增訪客"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"移除訪客"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"訪客"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"拍照"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"選擇圖片"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index bcc6369bb99a..f4ff6ec89d94 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -553,7 +553,8 @@
<string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Idala umsebenzisi omusha…"</string>
<string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
- <string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
+ <!-- no translation found for guest_exit_guest (4754204715192830850) -->
+ <skip />
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
index a92105320a62..02d1c2e65c8d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java
@@ -23,12 +23,12 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.SubsystemRestartTrackingCallback;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
-import android.text.TextUtils;
import android.util.Log;
/**
@@ -58,35 +58,18 @@ public class ConnectivitySubsystemsRecoveryManager {
private boolean mWifiRestartInProgress = false;
private boolean mTelephonyRestartInProgress = false;
private RecoveryStatusCallback mCurrentRecoveryCallback = null;
- private final BroadcastReceiver mWifiMonitor = new BroadcastReceiver() {
+ private final SubsystemRestartTrackingCallback mWifiSubsystemRestartTrackingCallback =
+ new SubsystemRestartTrackingCallback() {
@Override
- public void onReceive(Context context, Intent intent) {
- if (!mWifiRestartInProgress || mCurrentRecoveryCallback == null) {
- stopTrackingWifiRestart();
- }
-
- // TODO: harden this code to avoid race condition. What if WiFi toggled just before
- // recovery triggered. Either use new broadcasts from framework or detect more state
- // changes.
- boolean recoveryDone = false;
- if (TextUtils.equals(intent.getAction(), WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- if (intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED) {
- recoveryDone = true;
- }
- } else if (TextUtils.equals(intent.getAction(),
- WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
- if (intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE,
- WifiManager.WIFI_AP_STATE_FAILED) == WifiManager.WIFI_AP_STATE_ENABLED) {
- recoveryDone = true;
- }
- }
+ public void onSubsystemRestarting() {
+ // going to do nothing on this - already assuming that subsystem is restarting
+ }
- if (recoveryDone) {
- mWifiRestartInProgress = false;
- stopTrackingWifiRestart();
- checkIfAllSubsystemsRestartsAreDone();
- }
+ @Override
+ public void onSubsystemRestarted() {
+ mWifiRestartInProgress = false;
+ stopTrackingWifiRestart();
+ checkIfAllSubsystemsRestartsAreDone();
}
};
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@@ -208,13 +191,13 @@ public class ConnectivitySubsystemsRecoveryManager {
}
private void startTrackingWifiRestart() {
- IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
- filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- mContext.registerReceiver(mWifiMonitor, filter, null, mHandler);
+ mWifiManager.registerSubsystemRestartTrackingCallback(new HandlerExecutor(mHandler),
+ mWifiSubsystemRestartTrackingCallback);
}
private void stopTrackingWifiRestart() {
- mContext.unregisterReceiver(mWifiMonitor);
+ mWifiManager.unregisterWifiSubsystemRestartTrackingCallback(
+ mWifiSubsystemRestartTrackingCallback);
}
private void startTrackingTelephonyRestart() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
index 99d2ff7f322f..695b5b6ba061 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/emergencynumber/EmergencyNumberUtilsTest.java
@@ -18,15 +18,21 @@ package com.android.settingslib.emergencynumber;
import static android.telephony.emergency.EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE;
+import static com.android.settingslib.emergencynumber.EmergencyNumberUtils.EMERGENCY_GESTURE_CALL_NUMBER;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.provider.Settings;
+import android.net.Uri;
+import android.os.Bundle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
@@ -38,7 +44,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@@ -55,12 +60,15 @@ public class EmergencyNumberUtilsTest {
private PackageManager mPackageManager;
@Mock
private TelephonyManager mTelephonyManager;
+ @Mock
+ ContentResolver mContentResolver;
private EmergencyNumberUtils mUtils;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
}
@Test
@@ -89,11 +97,10 @@ public class EmergencyNumberUtilsTest {
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
addEmergencyNumberToTelephony();
- ContentResolver resolver = RuntimeEnvironment.application.getContentResolver();
- when(mContext.getContentResolver()).thenReturn(resolver);
- Settings.Secure.putString(resolver, Settings.Secure.EMERGENCY_GESTURE_CALL_NUMBER,
- USER_OVERRIDE_EMERGENCY_NUMBER);
-
+ Bundle bundle = new Bundle();
+ bundle.putString(EMERGENCY_GESTURE_CALL_NUMBER, USER_OVERRIDE_EMERGENCY_NUMBER);
+ when(mContentResolver.call(any(Uri.class), anyString(), nullable(String.class), nullable(
+ Bundle.class))).thenReturn(bundle);
mUtils = new EmergencyNumberUtils(mContext);
assertThat(mUtils.getPoliceNumber()).isEqualTo(USER_OVERRIDE_EMERGENCY_NUMBER);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f83f6706d55b..0a43014dee68 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -120,6 +120,7 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+ <uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
<uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
<uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
<uses-permission android:name="android.permission.READ_LOWPAN_CREDENTIAL"/>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 459d162c65db..c027f8df1f66 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن سريعًا"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن ببطء"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • التحسين لسلامة البطارية"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • التحسين للحفاظ على سلامة البطارية"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"توصيل جهاز الشحن."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"اضغط على \"القائمة\" لإلغاء التأمين."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"الشبكة مؤمّنة"</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 346874060759..4220526635f7 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Puni se"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo se puni"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo se puni"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizuje se radi dobrog stanja baterije"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizuje se radi boljeg stanja baterije"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Priključite punjač."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Pritisnite Meni da biste otključali."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 0911efade706..dc4ee693d89c 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бързо"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бавно"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Оптимизиране за състоянието на батерията"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Оптимизиране с цел състоянието на батерията"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Свържете зарядното си устройство."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натиснете „Меню“, за да отключите."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заключена"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 421ddb6d31e6..2e3b4af4a68f 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant ràpidament"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant lentament"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està optimitzant per mantenir el bon estat de la bateria"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està optimitzant per preservar l\'estat de la bateria"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Connecta el carregador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Prem Menú per desbloquejar."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index ce8ef202a038..93fe516a8aa6 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bizkor kargatzen"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mantso kargatzen"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizatzen bateria egoera onean mantentzeko"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizatzen, bateria egoera onean mantentzeko"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Konektatu kargagailua."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Desblokeatzeko, sakatu Menua."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index f2156252e241..d18690103c96 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"En recharge : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"En recharge rapide : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimisation en fonction de la santé de la pile"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimisation pour préserver la pile"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Branchez votre chargeur."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur la touche Menu pour déverrouiller l\'appareil."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 01a0fac58016..f8c5ebac9517 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizando para manter a batería en bo estado"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optimizando a preservación da batería"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Conecta o cargador."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Preme Menú para desbloquear."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index c8ed16d10327..ab07ba46c14d 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորում"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Արագ լիցքավորում"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Դանդաղ լիցքավորում"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Օպտիմալացվում է մարտկոցի աշխատանքային հզորության համար"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Օպտիմալացվում է մարտկոցի պահպանման համար"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Միացրեք լիցքավորիչը:"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ապակողպելու համար սեղմեք Ընտրացանկը:"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 3f3bec9b8c8c..bb8a908d20f7 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í hleðslu"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hröð hleðsla"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hæg hleðsla"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Fínstillir til að bæta rafhlöðuendingu"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Fínstillir fyrir rafhlöðuendingu"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Tengdu hleðslutækið."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ýttu á valmyndarhnappinn til að taka úr lás."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 47d17ce57892..c1baadf47de0 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • In carica"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica veloce"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica lenta"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • È in corso l\'ottimizzazione per l\'integrità della batteria"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ottimizzazione per integrità batteria"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Collega il caricabatterie."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Premi Menu per sbloccare."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index b20cb05ea86f..8e701fe86430 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталуда"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жылдам зарядталуда"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Баяу зарядталуда"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяның жұмыс істеу қабілеті оңтайландырылуда"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батарея жұмысын оңтайландыру"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Зарядтағышты қосыңыз."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index a52712379776..96865419cbf7 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ವೇಗವಾಗಿ ಚಾರ್ಜ್‌ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಬ್ಯಾಟರಿಯ ಆರೋಗ್ಯಕ್ಕಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಬ್ಯಾಟರಿಯ ಸುಸ್ಥಿತಿಗಾಗಿ ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"ನಿಮ್ಮ ಚಾರ್ಜರ್ ಸಂಪರ್ಕಗೊಳಿಸಿ."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್‌ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index 2ff4a22d6737..13c152f8f38b 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэж байна"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Хурдан цэнэглэж байна"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Удаан цэнэглэж байна"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батарейн чанарыг оновчилж байна"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батарейн барилтыг оновчилж байна"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Цэнэглэгчээ холбоно уу."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Түгжээг тайлах бол цэсийг дарна уу."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 43d549c92e6b..04419e039b58 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬੈਟਰੀ ਸਥਿਤੀ ਲਈ ਅਨੁਕੂਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬੈਟਰੀ ਦੀ ਸਥਿਤੀ ਲਈ ਅਨੁਕੂਲ ਬਣਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"ਆਪਣਾ ਚਾਰਜਰ ਕਨੈਕਟ ਕਰੋ।"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ਅਣਲਾਕ ਕਰਨ ਲਈ \"ਮੀਨੂ\" ਦਬਾਓ।"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 76f755c2b96a..01427be041ad 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Szybkie ładowanie"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wolne ładowanie"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optymalizuję, by utrzymać baterię w dobrym stanie"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Optymalizuję, aby utrzymać baterię w dobrym stanie"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Podłącz ładowarkę."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Naciśnij Menu, aby odblokować."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 3a6078224be2..64609b302069 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණය වෙමින්"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින්"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • සෙමින් ආරෝපණය වෙමින්"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • බැටරි සෞඛ්‍යය සඳහා ප්‍රශස්ත කරමින්"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • බැටරි ආයු කාලය වැඩි දියුණු කරමින්"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"ඔබගේ ආරෝපකයට සම්බන්ධ කරන්න."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"අගුලු හැරීමට මෙනුව ඔබන්න."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 90b8a3e362fd..7ca04ce8198a 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Пуни се"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо се пуни"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Споро се пуни"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Оптимизује се ради доброг стања батерије"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Оптимизује се ради бољег стања батерије"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Прикључите пуњач."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притисните Мени да бисте откључали."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежа је закључана"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index c69a8f56b933..990253a7862f 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జ్ అవుతోంది"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • వేగంగా ఛార్జ్ అవుతోంది"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • బ్యాటరీ జీవితకాలాన్ని ఆప్టిమైజ్ చేయడం కోసం"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • బ్యాటరీ జీవితకాలాన్ని పెంచడం కోసం ఆప్టిమైజ్ చేస్తోంది"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"మీ ఛార్జర్‌ను కనెక్ట్ చేయండి."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"అన్‌లాక్ చేయడానికి మెనుని నొక్కండి."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్‌వర్క్ లాక్ చేయబడింది"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index a16576d37e9c..62950e29c70e 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Швидке заряджання"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Повільне заряджання"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Стан акумулятора оптимізується"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Оптимізація для збереження заряду акумулятора"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Підключіть зарядний пристрій."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натисніть меню, щоб розблокувати."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 44e419180f6a..f2ca159bff0d 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvat olmoqda"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tezkor quvvat olmoqda"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sekin quvvat olmoqda"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareya quvvati muvozanatlanmoqda"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareya uchun optimizatsiya"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"Quvvatlash moslamasini ulang."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Qulfdan chiqarish uchun Menyu tugmasini bosing."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 1054e36fc048..b4006e8b7341 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充電"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在快速充電"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> •正在慢速充電"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在優化電池狀態"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 優化電池效能"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"請連接充電器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按下 [選單] 即可解鎖。"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"網絡已鎖定"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 7efa2f934d95..757bf56f3050 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 針對電池狀態進行最佳化調整"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="1158086783302116604">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 最佳化調整電池狀態"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"請連接充電器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"按選單鍵解鎖。"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index fa4eea5a805f..fe4ba63fe6c3 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuwe gebruiker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nie gekoppel nie"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk nie"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi af"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Wys profiel"</string>
<string name="user_add_user" msgid="4336657383006913022">"Voeg gebruiker by"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuwe gebruiker"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Verwyder gas?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwyder"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gas!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Wiil jy jou sessie voortsit?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Begin van voor af"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 5a22d919e912..9149aa636180 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ተጠቃሚ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"አዲስ ተጠቃሚ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"አልተገናኘም"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ምንም አውታረ መረብ የለም"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ጠፍቷል"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"እንግዳ ይወገድ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"አስወግድ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 39afa8362861..0146fcddf4fd 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -357,6 +357,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"المستخدم"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"مستخدم جديد"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ليست متصلة"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"لا تتوفر شبكة"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‏إيقاف Wi-Fi"</string>
@@ -462,9 +464,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"هل تريد إزالة جلسة الضيف؟"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"إزالة"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index cfb300941c74..3c206f2949a3 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ব্যৱহাৰকাৰী"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যৱহাৰকাৰী"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ৱাই-ফাই"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"সংযোগ হৈ থকা নাই"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"নেটৱৰ্ক নাই"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ৱাই-ফাই অফ"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি আঁতৰাবনে?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ সকলো এপ্ আৰু ডেটা মচা হ\'ব।"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"আঁতৰাওক"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"আপোনাক পুনৰাই স্বাগতম জনাইছোঁ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপুনি আপোনাৰ ছেশ্বন অব্যাহত ৰাখিব বিচাৰেনে?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আকৌ আৰম্ভ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index fef70c3ff17b..67e1718a03fb 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"İstifadəçi"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni istifadəçi"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlantı yoxdur"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Şəbəkə yoxdur"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi sönülüdür"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"İstifadəçi əlavə edin"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Yeni istifadəçi"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Qonaq silinsin?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Yığışdır"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Xoş gəlmisiniz!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Sessiya davam etsin?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Yenidən başlayı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 978b46d13c38..ae8ffbfbe304 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Veza nije uspostavljena"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string>
@@ -456,9 +458,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaži profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li da uklonite gosta?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 641134eb7230..b90d57e7ff5d 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Карыстальнік"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новы карыстальнік"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма падключэння"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма сеткi"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi адключаны"</string>
@@ -458,9 +460,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Выдаліць госця?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Выдаліць"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 0848383d7785..bfc8ef1d1151 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Потребител"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов потребител"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Няма връзка"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Няма мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е изключен"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се премахне ли гостът?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Премахване"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дошли отново в сесията като гост!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Искате ли да продължите сесията си?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Започване отначало"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 109990189e1e..c41a43404628 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -85,8 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"স্ক্রিনশট সেভ করা যায়নি"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"স্ক্রিনশট সেভ করার আগে ডিভাইসটি অবশ্যই আনলক করতে হবে"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"আবার স্ক্রিনশট নেওয়ার চেষ্টা করুন"</string>
- <!-- no translation found for screenshot_failed_to_save_text (7232739948999195960) -->
- <skip />
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"স্ক্রিনশট সেভ করা যায়নি"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"এই অ্যাপ বা আপনার প্রতিষ্ঠান স্ক্রিনশট নেওয়ার অনুমতি দেয়নি"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"এডিট করুন"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"স্ক্রিনশট এডিট করুন"</string>
@@ -354,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ব্যবহারকারী"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"নতুন ব্যবহারকারী"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ওয়াই-ফাই"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"সংযুক্ত নয়"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"কোনো নেটওয়ার্ক নেই"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ওয়াই-ফাই বন্ধ"</string>
@@ -455,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি সরাবেন?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ্লিকেশান ও ডেটা মুছে ফেলা হবে।"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"সরান"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি অবিরত রাখতে চান?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 3c81a4b1deb9..9a2877351c51 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi je isključen"</string>
@@ -456,9 +458,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaži profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li ukloniti gosta?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i svi podaci iz ove sesije bit će izbrisani."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ef419ab2bd79..426005af098a 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuari"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuari nou"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Desconnectat"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hi ha cap xarxa"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desconnectada"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra el perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vols suprimir el convidat?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Suprimeix"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 972232fd8768..3e015ec7c720 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Uživatel"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový uživatel"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepřipojeno"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žádná síť"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi vypnuta"</string>
@@ -458,9 +460,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobrazit profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstranit hosta?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstranit"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
diff --git a/packages/SystemUI/res/values-cs/strings_tv.xml b/packages/SystemUI/res/values-cs/strings_tv.xml
index 0a9850c7b7a7..eeab0d9d95a2 100644
--- a/packages/SystemUI/res/values-cs/strings_tv.xml
+++ b/packages/SystemUI/res/values-cs/strings_tv.xml
@@ -23,7 +23,7 @@
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikace %1$s použila mikrofon"</string>
<string name="notification_vpn_connected" msgid="3891023882833274730">"Síť VPN je připojena"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"Síť VPN je odpojena"</string>
- <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prostřednictvím aplikace <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Přes <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Oznámení"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Žádná oznámení"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index eb5f8caa2b78..8fd48b1bdd02 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Bruger"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruger"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke forbundet"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Intet netværk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi slået fra"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gæsten?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 66fb7eb480fe..84b63ba2db37 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Nutzer"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Neuer Nutzer"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nicht verbunden"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Kein Netz"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN aus"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil öffnen"</string>
<string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast entfernen?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Entfernen"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 40e229426d2b..bec78c0e57d6 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Χρήστης"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Νέος χρήστης"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Μη συνδεδεμένο"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Κανένα δίκτυο"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ανενεργό"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Κατάργηση επισκέπτη;"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Κατάργηση"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Επισκέπτη , καλώς όρισες ξανά!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index ca81ed6e7e17..21cac18abeb5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"End Guest session?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"End session"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 89537e905720..7ac4c0df0ca1 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"End Guest session?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"End session"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index ca81ed6e7e17..21cac18abeb5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"End Guest session?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"End session"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index ca81ed6e7e17..21cac18abeb5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"New user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Not Connected"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Off"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Show profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"Add user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"New user"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remove guest?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"End Guest session?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remove"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"End session"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome back, guest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Do you want to continue your session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start again"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 6fa2171b9041..2f30c412a159 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎User‎‏‎‎‏‎"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‎‏‎‎New user‎‏‎‎‏‎"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎Wi-Fi‎‏‎‎‏‎"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‎‎Not Connected‎‏‎‎‏‎"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎No Network‎‏‎‎‏‎"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎Wi-Fi Off‎‏‎‎‏‎"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‎‎Show profile‎‏‎‎‏‎"</string>
<string name="user_add_user" msgid="4336657383006913022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎Add user‎‏‎‎‏‎"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‎New user‎‏‎‎‏‎"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎Remove guest?‎‏‎‎‏‎"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎End guest session?‎‏‎‎‏‎"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‏‎All apps and data in this session will be deleted.‎‏‎‎‏‎"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎Remove‎‏‎‎‏‎"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‎End session‎‏‎‎‏‎"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‎‎Welcome back, guest!‎‏‎‎‏‎"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎Do you want to continue your session?‎‏‎‎‏‎"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‎‏‎Start over‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e9a27854622a..7ef9cdb96df7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Usuario nuevo"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Sin conexión"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sin red"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivada"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Agregar usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuario nuevo"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Eliminar invitado?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"¿Quieres finalizar la sesión de invitado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eliminar"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalizar sesión"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenido nuevamente, invitado."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 11ff9af1f7e7..6c6b511e2fe4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -85,8 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"No se ha podido guardar la captura de pantalla"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"El dispositivo debe desbloquearse para que se pueda guardar la captura de pantalla"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Vuelve a intentar hacer la captura de pantalla"</string>
- <!-- no translation found for screenshot_failed_to_save_text (7232739948999195960) -->
- <skip />
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"No se puede guardar la captura de pantalla"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"La aplicación o tu organización no permiten realizar capturas de pantalla"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"Editar"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"Editar captura de pantalla"</string>
@@ -354,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuevo usuario"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"No conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"No hay red."</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desactivado"</string>
@@ -455,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Añadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuevo usuario"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"¿Finalizar sesión de invitado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Finalizar sesión"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hola de nuevo, invitado"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 27a9df054c4f..c64a07e3b61b 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Kasutaja"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uus kasutaja"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ühendus puudub"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Võrku pole"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi-ühendus on väljas"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Kuva profiil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Kas eemaldada külaline?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eemalda"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b2dc3d6361d2..5047cf17fefd 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Erabiltzailea"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Erabiltzaile berria"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifia"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Konektatu gabe"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ez dago sarerik"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi konexioa desaktibatuta"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Erakutsi profila"</string>
<string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzailea"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gonbidatua kendu nahi duzu?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Gonbidatuentzako saioa amaitu nahi duzu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kendu"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Amaitu saioa"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 214f5c2c616c..34c6bf66f64c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"کاربر"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"کاربر جدید"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"متصل نیست"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"شبکه‌ای موجود نیست"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‏Wi-Fi خاموش است"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مهمان حذف شود؟"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"حذف"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد می‌گوییم!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cb60ff4c4ebe..5486e39133d8 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Käyttäjä"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Uusi käyttäjä"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ei yhteyttä"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ei verkkoa"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-yhteys pois käytöstä"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Näytä profiili"</string>
<string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Poistetaaanko vieras?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Poista"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 17752c5d2c8a..63f65e08e189 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 39d82ef44c6a..ebf199bfae90 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Utilisateur"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nouvel utilisateur"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connecté"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Aucun réseau"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi désactivé"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afficher le profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 6494e0afc5e8..36f7f4cd9fb7 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuario"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuario"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non conectada"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Non hai rede"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi desactivada"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Queres eliminar o invitado?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eliminar"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 369fd1d51f14..66423e46c4e5 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"વપરાશકર્તા"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"નવો વપરાશકર્તા"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"વાઇ-ફાઇ"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"કનેક્ટ થયેલ નથી"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"કોઈ નેટવર્ક નથી"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"વાઇ-ફાઇ બંધ"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"અતિથિ દૂર કરીએ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ્લિકેશનો અને ડેટા કાઢી નાખવામાં આવશે."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"દૂર કરો"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ફરી સ્વાગત છે, અતિથિ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"શું તમે તમારું સત્ર ચાલુ કરવા માંગો છો?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"શરૂ કરો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 0b16f527e46a..65cba2f9dc09 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -85,7 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रीनशॉट सेव नहीं किया जा सका"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"स्क्रीनशॉट सेव करने के लिए डिवाइस का अनलॉक होना ज़रूरी है"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट दोबारा लेने की कोशिश करें"</string>
- <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रीनशॉट को सेव नहीं किया जा सका"</string>
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रीनशॉट को सेव नहीं किया जा सकता"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ऐप्लिकेशन या आपका संगठन स्क्रीनशॉट लेने की अनुमति नहीं देता"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"बदलाव करें"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट में बदलाव करें"</string>
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"उपयोगकर्ता"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नया उपयोगकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाई-फ़ाई"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट नहीं है"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"कोई नेटवर्क नहीं"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाई-फ़ाई बंद"</string>
@@ -456,9 +458,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि को निकालें?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्स और डेटा को हटा दिया जाएगा."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"निकालें"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथि, आपका फिर से स्वागत है!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आप अपना सत्र जारी रखना चाहते हैं?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 2f13421590ae..7d60619e2f02 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Korisnik"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novi korisnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nije povezano"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nema mreže"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi isključen"</string>
@@ -456,9 +458,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string>
<string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index a7b3cc315980..2ee8913f00d1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Felhasználó"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Új felhasználó"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nincs kapcsolat"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nincs hálózat"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi kikapcsolva"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profil megjelenítése"</string>
<string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Eltávolítja a vendég munkamenetet?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eltávolítás"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string>
diff --git a/packages/SystemUI/res/values-hu/strings_tv.xml b/packages/SystemUI/res/values-hu/strings_tv.xml
index 78d6099b74a0..91183af142a5 100644
--- a/packages/SystemUI/res/values-hu/strings_tv.xml
+++ b/packages/SystemUI/res/values-hu/strings_tv.xml
@@ -23,7 +23,7 @@
<string name="app_accessed_mic" msgid="2754428675130470196">"A(z) %1$s hozzáfért a mikrofonhoz"</string>
<string name="notification_vpn_connected" msgid="3891023882833274730">"A VPN-kapcsolat létrejött"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"A VPN-kapcsolat megszakadt"</string>
- <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"A következő szolgáltatás használatával: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Ezzel: <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Értesítések"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Nincs értesítés"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index fed73da0f120..18af1eaf17e3 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Օգտատեր"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Նոր օգտատեր"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Միացված չէ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ցանց չկա"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi-ը անջատված է"</string>
@@ -454,9 +456,9 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Հեռացնե՞լ հյուրին:"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Ավարտե՞լ հյուրի աշխատաշրջանը"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Հեռացնել"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Ավարտել աշխատաշրջանը"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր:"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Դուք ցանկանու՞մ եք շարունակել ձեր գործողությունը:"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Սկսել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 7ae3e5d7edb4..4a048bb638ef 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baru"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Terhubung"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tidak Ada Jaringan"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Mati"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tampilkan profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Hapus tamu?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hapus"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 0361ba4db718..10e11fc64d7b 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Notandi"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nýr notandi"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Engin tenging"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ekkert net"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Slökkt á Wi-Fi"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Sýna snið"</string>
<string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Fjarlægja gest?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjarlægja"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 948faf1ccf72..24e3f474f1fe 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Utente"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nuovo utente"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Non connessa"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nessuna rete"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi disattivato"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostra profilo"</string>
<string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Rimuovere l\'ospite?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Rimuovi"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bentornato, ospite."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index d20623e0efa1..76dbdf99ca50 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -35,7 +35,7 @@
<string name="battery_low_why" msgid="2056750982959359863">"הגדרות"</string>
<string name="battery_saver_confirmation_title" msgid="1234998463717398453">"להפעיל את תכונת החיסכון בסוללה?"</string>
<string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"מידע על מצב החיסכון בסוללה"</string>
- <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעל"</string>
+ <string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"הפעלה"</string>
<string name="battery_saver_start_action" msgid="4553256017945469937">"הפעלת תכונת החיסכון בסוללה"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"הגדרות"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
@@ -278,8 +278,8 @@
<string name="accessibility_quick_settings_flashlight_changed_on" msgid="4747870681508334200">"הפנס הופעל."</string>
<string name="accessibility_quick_settings_color_inversion_changed_off" msgid="7548045840282925393">"היפוך צבעים כבוי."</string>
<string name="accessibility_quick_settings_color_inversion_changed_on" msgid="4711141858364404084">"היפוך צבעים מופעל."</string>
- <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"נקודה לשיתוף אינטרנט בנייד כבויה."</string>
- <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"נקודה לשיתוף אינטרנט בנייד מופעלת."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_off" msgid="7002061268910095176">"‏נקודת האינטרנט (hotspot) כבויה."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2576895346762408840">"‏נקודת האינטרנט (hotspot) מופעלת."</string>
<string name="accessibility_casting_turned_off" msgid="1387906158563374962">"העברת המסך הופסקה."</string>
<string name="accessibility_quick_settings_work_mode_off" msgid="562749867895549696">"מצב עבודה כבוי."</string>
<string name="accessibility_quick_settings_work_mode_on" msgid="2779253456042059110">"מצב עבודה מופעל."</string>
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"משתמש"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"משתמש חדש"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"אין חיבור"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"אין רשת"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‏Wi-Fi כבוי"</string>
@@ -377,7 +379,7 @@
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"מחובר, הסוללה ב-<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="quick_settings_connecting" msgid="2381969772953268809">"מתחבר..."</string>
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"שיתוף אינטרנט בין ניידים"</string>
- <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"נקודה לשיתוף אינטרנט"</string>
+ <string name="quick_settings_hotspot_label" msgid="1199196300038363424">"‏נקודת אינטרנט (hotspot)"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"ההפעלה מתבצעת…"</string>
<string name="quick_settings_hotspot_secondary_label_data_saver_enabled" msgid="1280433136266439372">"חוסך הנתונים פועל"</string>
<plurals name="quick_settings_hotspot_secondary_label_num_devices" formatted="false" msgid="3142308865165871976">
@@ -458,9 +460,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"להסיר אורח?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בפעילות זו באתר יימחקו."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"הסר"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ברצוני להתחיל מחדש"</string>
@@ -649,7 +653,7 @@
<string name="alarm_template" msgid="2234991538018805736">"בשעה <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"ב-<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="accessibility_quick_settings_detail" msgid="544463655956179791">"הגדרות מהירות, <xliff:g id="TITLE">%s</xliff:g>."</string>
- <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"נקודה לשיתוף אינטרנט"</string>
+ <string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"‏נקודת אינטרנט (hotspot)"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"פרופיל עבודה"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"מהנה בשביל חלק מהאנשים, אבל לא בשביל כולם"</string>
<string name="tuner_warning" msgid="1861736288458481650">"‏System UI Tuner מספק לך דרכים נוספות להתאים אישית את ממשק המשתמש של Android. התכונות הניסיוניות האלה עשויות להשתנות, להתקלקל או להיעלם בגרסאות עתידיות. המשך בזהירות."</string>
@@ -666,7 +670,7 @@
<string name="experimental" msgid="3549865454812314826">"ניסיוני"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"‏האם להפעיל את ה-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
- <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"הפעל"</string>
+ <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"הפעלה"</string>
<string name="show_silently" msgid="5629369640872236299">"הצגת התראות בלי להשמיע צליל"</string>
<string name="block" msgid="188483833983476566">"חסימת כל ההתראות"</string>
<string name="do_not_silence" msgid="4982217934250511227">"לא להשתיק"</string>
diff --git a/packages/SystemUI/res/values-iw/strings_tv.xml b/packages/SystemUI/res/values-iw/strings_tv.xml
index 7483116177f6..1258f0d42aa0 100644
--- a/packages/SystemUI/res/values-iw/strings_tv.xml
+++ b/packages/SystemUI/res/values-iw/strings_tv.xml
@@ -21,8 +21,8 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"המיקרופון פעיל"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"‏%1$s קיבלה גישה למיקרופון שלך"</string>
- <string name="notification_vpn_connected" msgid="3891023882833274730">"‏VPN מחובר"</string>
- <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏VPN מנותק"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"‏ה-VPN מחובר"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"‏ה-VPN מנותק"</string>
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"באמצעות <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"התראות"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"אין התראות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 3bb841d21694..b4edfe5c38dc 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ユーザー"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新しいユーザー"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"接続されていません"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ネットワークなし"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi OFF"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ゲストを削除しますか?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"削除"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 3e3405e23706..26bde65e0ba3 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"მომხმარებელი"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ახალი მომხმარებელი"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"არ არის დაკავშირებული."</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ქსელი არ არის"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi გამორთულია"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"სტუმრის ამოშლა?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ამოშლა"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"სტუმარო, გვიხარია, რომ დაბრუნდით!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"გსურთ, თქვენი სესიის გაგრძელება?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ხელახლა დაწყება"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 7cbb40b1ad34..9ce0a29649dc 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Пайдаланушы"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңа пайдаланушы"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Жалғанбаған"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желі жоқ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өшірулі"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Қонақты жою керек пе?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып тастау"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e15cc9218269..1e6c7fa6ebea 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"អ្នកប្រើ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"អ្នកប្រើ​ថ្មី"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"មិន​បាន​តភ្ជាប់"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"គ្មាន​បណ្ដាញ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"វ៉ាយហ្វាយ​បានបិទ"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"លុប​ភ្ញៀវ​?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ទិន្នន័យ និង​កម្មវិធី​ទាំងអស់​ក្នុង​សម័យ​នេះ​នឹង​ត្រូវ​បាន​លុប។"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"លុបចេញ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"សូម​ស្វាគមន៍​ការ​ត្រឡប់​មកវិញ, ភ្ញៀវ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​សម័យ​របស់​អ្នក​?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើម"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 177db59697f5..2958b2947de0 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ಬಳಕೆದಾರ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ವೈ-ಫೈ"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ನೆಟ್‌ವರ್ಕ್ ಇಲ್ಲ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ವೈ-ಫೈ ಆಫ್"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್‌ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ತೆಗೆದುಹಾಕಿ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index eb81396257a6..cd613b647e38 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"사용자"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"신규 사용자"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"연결되어 있지 않음"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"네트워크가 연결되지 않음"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 꺼짐"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 다시 시작"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index caa2b31647c1..e6053411b74a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Колдонуучу"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Жаңы колдонуучу"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Байланышкан жок"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Желе жок"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi өчүк"</string>
@@ -456,9 +458,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Конокту алып саласызбы?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана дайындар өчүрүлөт."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып салуу"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен, конок!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 5ed1d4b0416f..b8cc3ded31e8 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ຜູ້ໃຊ້"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ຜູ່ໃຊ້ໃໝ່"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi​-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ບໍ່ມີເຄືອຂ່າຍ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi​-Fi ປິດ"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ລຶບ​ແຂກ​ບໍ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ລຶບ​"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນ​ດີ​ຕ້ອນ​ຮັບ​ກັບ​ມາ, ຜູ່​ຢ້ຽມ​ຢາມ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 17d517cda3de..8a32436f2c0c 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Naudotojas"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Naujas naudotojas"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neprisijungta"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tinklo nėra"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"„Wi-Fi“ išjungta"</string>
@@ -458,9 +460,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Rodyti profilį"</string>
<string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pašalinti svečią?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Pašalinti"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 6fd32b59f175..56ce376dd147 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Lietotājs"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Jauns lietotājs"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nav izveidots savienojums"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nav tīkla"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ir izslēgts"</string>
@@ -456,9 +458,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Parādīt profilu"</string>
<string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vai noņemt viesi?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Noņemt"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 51f9b8c4d45a..fc83bb7ee46d 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нов корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не е поврзано"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мрежа"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi е исклучено"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 534faa719334..9cd041236c36 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ഉപയോക്താവ്"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"പുതിയ ഉപയോക്താവ്"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"വൈഫൈ"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"കണ‌ക്റ്റ് ചെയ്‌തിട്ടില്ല"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"നെറ്റ്‌വർക്ക് ഒന്നുമില്ല"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"വൈഫൈ ഓഫുചെയ്യുക"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"അതിഥിയെ നീക്കംചെയ്യണോ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ അപ്ലിക്കേഷനുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"നീക്കംചെയ്യുക"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥിയ്‌ക്ക് വീണ്ടും സ്വാഗതം!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 190e3e503798..b0159b027611 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Хэрэглэгч"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Шинэ хэрэглэгч"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Холбогдоогүй"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Сүлжээгүй"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi унтарсан"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Зочныг хасах уу?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ сешний бүх апп болон дата устах болно."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Хасах"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Тавтай морилно уу!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1f2e82e1c429..965b8958b458 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -85,8 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रीनशॉट सेव्ह करू शकलो नाही"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"स्क्रीनशॉट सेव्ह करण्याआधी डिव्हाइस अनलॉक करणे आवश्यक आहे"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रीनशॉट पुन्हा घेण्याचा प्रयत्न करा"</string>
- <!-- no translation found for screenshot_failed_to_save_text (7232739948999195960) -->
- <skip />
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रीनशॉट सेव्ह करू शकत नाही"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"अ‍ॅप किंवा आपल्या संस्थेद्वारे स्क्रीनशॉट घेण्याची अनुमती नाही"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"संपादित करा"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रीनशॉट संपादित करा"</string>
@@ -354,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"वापरकर्ता"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नवीन वापरकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"वाय-फाय"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"कनेक्ट केले नाही"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क नाही"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"वाय-फाय बंद"</string>
@@ -455,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथी काढायचे?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्‍हा स्‍वागत आहे!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 17fe32d3b2d5..b9b525ead63c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Pengguna"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Pengguna baharu"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Tidak Disambungkan"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tiada Rangkaian"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Dimatikan"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Tunjuk profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alih keluar tetamu?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alih keluar"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 610105eb6b4d..9801ec60c89e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"အသုံးပြုသူ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"အသုံးပြုသူ အသစ်"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ချိတ်ဆက်မထားပါ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ကွန်ရက်မရှိပါ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ဝိုင်ဖိုင်ပိတ်ရန်"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ဧည့်သည်ကို ဖယ်ထုတ်လိုက်ရမလား?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ဖယ်ထုတ်ပါ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ပြန်လာတာ ကြိုဆိုပါသည်၊ ဧည့်သည်!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်သည် သင်၏ ချိတ်ဆက်မှုကို ဆက်ပြုလုပ် လိုပါသလား?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"အစမှ ပြန်စပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b16f1e78af00..67242865b649 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Bruker"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny bruker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ikke tilkoblet"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ingen nettverk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi er av"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Vis profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gjesten?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index fb4dca094a5c..c104ffdf0dcd 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -85,8 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"यन्त्र अनलक गरेपछि मात्र स्क्रिनसट सुरक्षित गर्न सकिन्छ"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"स्क्रिनसट फेरि लिएर हेर्नुहोस्"</string>
- <!-- no translation found for screenshot_failed_to_save_text (7232739948999195960) -->
- <skip />
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"स्क्रिनसट सुरक्षित गर्न सकिएन"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"उक्त एप वा तपाईंको संगठनले स्क्रिनसटहरू लिन दिँदैन"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"सम्पादन गर्नुहोस्"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"स्क्रिनसट सम्पादन गर्नुहोस्"</string>
@@ -354,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"प्रयोगकर्ता"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"नयाँ प्रयोगकर्ता"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"जोडिएको छैन"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"नेटवर्क छैन"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi बन्द"</string>
@@ -455,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि हटाउने हो?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यस सत्रमा सबै एपहरू र डेटा मेटाइनेछ।"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"हटाउनुहोस्"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"पुनः स्वागत, अतिथि!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a858a1d79e0e..7d878170283f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Gebruiker"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nieuwe gebruiker"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wifi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Niet verbonden"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Geen netwerk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wifi uit"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profiel weergeven"</string>
<string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast verwijderen?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwijderen"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 4931b770cada..7d7b84f785f1 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ୟୁଜର୍‌"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ୱାଇ-ଫାଇ"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ସଂଯୁକ୍ତ ହୋଇନାହିଁ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ନେଟ୍‌ୱର୍କ ନାହିଁ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ୱାଇ-ଫାଇ ଅଫ୍‍"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ଅବଧିର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ଅବଧି ଜାରି ରଖିବାକୁ ଚାହାନ୍ତି କି?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index a2ff2b2932db..7d5bc96830a5 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -85,8 +85,7 @@
<string name="screenshot_failed_title" msgid="3259148215671936891">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
<string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਰੱਖਿਅਤ ਕੀਤੇ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਡੀਵਾਈਸ ਨੂੰ ਅਣਲਾਕ ਕੀਤਾ ਹੋਣਾ ਲਾਜ਼ਮੀ ਹੈ"</string>
<string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦੁਬਾਰਾ ਲੈ ਕੇ ਦੇਖੋ"</string>
- <!-- no translation found for screenshot_failed_to_save_text (7232739948999195960) -->
- <skip />
+ <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨੂੰ ਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੱਤੀ ਗਈ ਹੈ"</string>
<string name="screenshot_edit_label" msgid="8754981973544133050">"ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="screenshot_edit_description" msgid="3333092254706788906">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -354,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ਵਰਤੋਂਕਾਰ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"ਵਾਈ-ਫਾਈ"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ਕੋਈ ਨੈੱਟਵਰਕ ਨਹੀਂ"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ਵਾਈ-ਫਾਈ ਬੰਦ"</string>
@@ -455,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ਕੀ ਮਹਿਮਾਨ ਹਟਾਉਣਾ ਹੈ?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ਹਟਾਓ"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਸ਼ੁਰੂ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 99552857a17b..8a19e285463e 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Użytkownik"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nowy użytkownik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Brak połączenia"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Brak sieci"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi wyłączone"</string>
@@ -458,9 +460,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Pokaż profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Usunąć gościa?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Usuń"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, gościu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 9b7220fb3c52..57b924d4e6f8 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover convidado?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
@@ -836,7 +840,7 @@
<item msgid="7453955063378349599">"Inclinação à esquerda"</item>
<item msgid="5874146774389433072">"Inclinação à direita"</item>
</string-array>
- <string name="menu_ime" msgid="5677467548258017952">"Alternador de teclado"</string>
+ <string name="menu_ime" msgid="5677467548258017952">"Seletor de teclado"</string>
<string name="save" msgid="3392754183673848006">"Salvar"</string>
<string name="reset" msgid="8715144064608810383">"Redefinir"</string>
<string name="adjust_button_width" msgid="8313444823666482197">"Ajustar largura do botão"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9b5267781ee9..e39f757ce416 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizador"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo utilizador"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não Ligado"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem Rede"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Desligado"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as aplicações e dados desta sessão serão eliminados."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, caro(a) convidado(a)!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 9b7220fb3c52..57b924d4e6f8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Usuário"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Novo usuário"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Não conectado"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Sem rede"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi desligado"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Mostrar perfil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover convidado?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo, convidado."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
@@ -836,7 +840,7 @@
<item msgid="7453955063378349599">"Inclinação à esquerda"</item>
<item msgid="5874146774389433072">"Inclinação à direita"</item>
</string-array>
- <string name="menu_ime" msgid="5677467548258017952">"Alternador de teclado"</string>
+ <string name="menu_ime" msgid="5677467548258017952">"Seletor de teclado"</string>
<string name="save" msgid="3392754183673848006">"Salvar"</string>
<string name="reset" msgid="8715144064608810383">"Redefinir"</string>
<string name="adjust_button_width" msgid="8313444823666482197">"Ajustar largura do botão"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d0d01036a041..acbe80140c2f 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Utilizator"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Utilizator nou"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Neconectată"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nicio rețea"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi deconectat"</string>
@@ -456,9 +458,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Afișați profilul"</string>
<string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ștergeți invitatul?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ștergeți"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 1b1aa29db67c..c59bd2ae727d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Пользователь"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новый пользователь"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Нет соединения"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нет сети"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi выкл."</string>
@@ -458,9 +460,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Удалить аккаунт гостя?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Удалить"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
diff --git a/packages/SystemUI/res/values-ru/strings_tv.xml b/packages/SystemUI/res/values-ru/strings_tv.xml
index e08ade3bc065..8ce0dc203923 100644
--- a/packages/SystemUI/res/values-ru/strings_tv.xml
+++ b/packages/SystemUI/res/values-ru/strings_tv.xml
@@ -23,7 +23,7 @@
<string name="app_accessed_mic" msgid="2754428675130470196">"Приложение \"%1$s\" использовало доступ к микрофону."</string>
<string name="notification_vpn_connected" msgid="3891023882833274730">"VPN-подключение установлено"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN-подключение отключено"</string>
- <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Отправлено через <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Через приложение <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Уведомления"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Уведомлений нет."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 998161496f0c..a49ca863b3fa 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"පරිශීලක"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"නව පරිශීලකයා"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"සම්බන්ධ වී නොමැත"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ජාලයක් නැත"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi අක්‍රියයි"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"අමුත්තාන් ඉවත් කරන්නද?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ඉවත් කරන්න"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 470b02154b55..fe63b70f1c46 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Používateľ"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nový používateľ"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi‑Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nepripojené"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Žiadna sieť"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Sieť Wi‑Fi je vypnutá"</string>
@@ -458,9 +460,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Zobraziť profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstrániť hosťa?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrániť"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 08fdb5895d90..85956d6d0c72 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Uporabnik"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Nov uporabnik"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Povezava ni vzpostavljena"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ni omrežja"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi izklopljen"</string>
@@ -458,9 +460,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Prikaz profila"</string>
<string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite odstraniti gosta?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrani"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
diff --git a/packages/SystemUI/res/values-sl/strings_tv.xml b/packages/SystemUI/res/values-sl/strings_tv.xml
index 57d70c0c3ecb..1f66138c175a 100644
--- a/packages/SystemUI/res/values-sl/strings_tv.xml
+++ b/packages/SystemUI/res/values-sl/strings_tv.xml
@@ -21,8 +21,8 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon je aktiven"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"Aplikacija %1$s je dostopala do mikrofona"</string>
- <string name="notification_vpn_connected" msgid="3891023882833274730">"Povezava z navideznim zasebnim omrežjem je vzpostavljena"</string>
- <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Povezava z navideznim zasebnim omrežjem je prekinjena"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"Povezava z omrežjem VPN je vzpostavljena"</string>
+ <string name="notification_vpn_disconnected" msgid="7150747626448044843">"Povezava z omrežjem VPN je prekinjena"</string>
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Prek storitve <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Obvestila"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Ni obvestil"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index aaee22511860..733db0e018a8 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -57,15 +57,15 @@
<string name="label_view" msgid="6815442985276363364">"Pamje"</string>
<string name="always_use_device" msgid="210535878779644679">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_DEVICE">%2$s</xliff:g>"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"Hap gjithmonë <xliff:g id="APPLICATION">%1$s</xliff:g> kur lidhet <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>"</string>
- <string name="usb_debugging_title" msgid="8274884945238642726">"Të lejohet korrigjimi i USB-së?"</string>
+ <string name="usb_debugging_title" msgid="8274884945238642726">"Të lejohet korrigjimi përmes USB-së?"</string>
<string name="usb_debugging_message" msgid="5794616114463921773">"Gjurma e gishtit të tastit \"RSA\" së kompjuterit është:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
<string name="usb_debugging_always" msgid="4003121804294739548">"Lejo gjithmonë nga ky kompjuter"</string>
<string name="usb_debugging_allow" msgid="1722643858015321328">"Lejo"</string>
- <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi i USB-së nuk lejohet"</string>
- <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin e USB-së. Për ta përdorur këtë funksion, kalo te përdoruesi parësor."</string>
+ <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Korrigjimi përmes USB-së nuk lejohet"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes USB-së. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string>
<string name="wifi_debugging_title" msgid="7300007687492186076">"Do ta lejosh korrigjimin përmes Wi-Fi në këtë rrjet?"</string>
<string name="wifi_debugging_message" msgid="5461204211731802995">"Emri i rrjetit (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nAdresa Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
- <string name="wifi_debugging_always" msgid="2968383799517975155">"Shfaq gjithmonë në këtë rrjet"</string>
+ <string name="wifi_debugging_always" msgid="2968383799517975155">"Lejo gjithmonë në këtë rrjet"</string>
<string name="wifi_debugging_allow" msgid="4573224609684957886">"Lejo"</string>
<string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Korrigjimi përmes Wi-Fi nuk lejohet"</string>
<string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Përdoruesi i identifikuar aktualisht në këtë pajisje nuk mund ta aktivizojë korrigjimin përmes Wi-Fi. Për ta përdorur këtë veçori, kalo te përdoruesi parësor."</string>
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Përdoruesi"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Përdorues i ri"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Nuk është i lidhur"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Nuk ka rrjet"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi është i çaktivizuar"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Shfaq profilin"</string>
<string name="user_add_user" msgid="4336657383006913022">"Shto përdorues"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Përdorues i ri"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Të hiqet i ftuari?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Dëshiron t\'i japësh fund sesionit të vizitorit?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hiq"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Jepi fund sesionit"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index d7645be711ed..c5414a4e3f80 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -354,6 +354,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Корисник"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Нови корисник"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WiFi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Веза није успостављена"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Нема мреже"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WiFi је искључен"</string>
@@ -456,9 +458,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Желите ли да уклоните госта?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Уклони"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8e5e79e809f5..d2c993a0985a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Användare"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Ny användare"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ej ansluten"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Inget nätverk"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi av"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Visa profil"</string>
<string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vill du ta bort gästen?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ta bort"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka gäst!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string>
diff --git a/packages/SystemUI/res/values-sv/strings_tv.xml b/packages/SystemUI/res/values-sv/strings_tv.xml
index d7261e6b1445..fd8fa4b1bb8e 100644
--- a/packages/SystemUI/res/values-sv/strings_tv.xml
+++ b/packages/SystemUI/res/values-sv/strings_tv.xml
@@ -23,7 +23,7 @@
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s har fått åtkomst till mikrofonen"</string>
<string name="notification_vpn_connected" msgid="3891023882833274730">"VPN är anslutet"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN är frånkopplat"</string>
- <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"via <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Aviseringar"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Inga aviseringar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 768fd8549d48..29045f3d69ae 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Mtumiaji"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Mtumiaji mpya"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Haijaunganishwa"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Hakuna Mtandao"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi Imezimwa"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Onyesha wasifu"</string>
<string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ungependa kumwondoa mgeni?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ondoa"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena, mwalikwa!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza tena"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index efdace48ff8e..2ca67201d387 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"பயனர்"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"புதியவர்"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"வைஃபை"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"இணைக்கப்படவில்லை"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"நெட்வொர்க் இல்லை"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"வைஃபையை முடக்கு"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"கெஸ்ட்டை அகற்றவா?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா பயன்பாடுகளும், தரவும் நீக்கப்படும்."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"அகற்று"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 36a5de721451..9ce5fc745580 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"వినియోగదారు"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"కొత్త వినియోగదారు"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"కనెక్ట్ చేయబడలేదు"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"నెట్‌వర్క్ లేదు"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi ఆఫ్‌లో ఉంది"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"అతిథిని తీసివేయాలా?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని అనువర్తనాలు మరియు డేటా తొలగించబడతాయి."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"తీసివేయి"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"పునఃస్వాగతం, అతిథి!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 5dd4400e9ece..900012eb267d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -93,7 +93,7 @@
<string name="screenshot_scroll_description" msgid="7855773867093272175">"เลื่อนจับภาพหน้าจอ"</string>
<string name="screenshot_dismiss_description" msgid="4702341245899508786">"ปิดภาพหน้าจอ"</string>
<string name="screenshot_preview_description" msgid="7606510140714080474">"ตัวอย่างภาพหน้าจอ"</string>
- <string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมอัดหน้าจอ"</string>
+ <string name="screenrecord_name" msgid="2596401223859996572">"โปรแกรมบันทึกหน้าจอ"</string>
<string name="screenrecord_background_processing_label" msgid="7244617554884238898">"กำลังประมวลผลการอัดหน้าจอ"</string>
<string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
<string name="screenrecord_start_label" msgid="1750350278888217473">"เริ่มบันทึกเลยไหม"</string>
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"ผู้ใช้"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"ผู้ใช้ใหม่"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"ไม่ได้เชื่อมต่อ"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"ไม่มีเครือข่าย"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"ปิด WiFi"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ต้องการนำผู้เข้าร่วมออกไหม"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"นำออก"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับท่านผู้เยี่ยมชมกลับมาอีกครั้ง!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
@@ -744,7 +748,7 @@
<string name="notification_conversation_home_screen" msgid="8347136037958438935">"เพิ่มลงในหน้าจอหลัก"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
<string name="notification_menu_gear_description" msgid="6429668976593634862">"ส่วนควบคุมการแจ้งเตือน"</string>
- <string name="notification_menu_snooze_description" msgid="4740133348901973244">"ตัวเลือกการปิดเสียงแจ้งเตือนชั่วคราว"</string>
+ <string name="notification_menu_snooze_description" msgid="4740133348901973244">"ตัวเลือกการเลื่อนการแจ้งเตือน"</string>
<string name="notification_menu_snooze_action" msgid="5415729610393475019">"เตือนฉัน"</string>
<string name="notification_menu_settings_action" msgid="7085494017202764285">"การตั้งค่า"</string>
<string name="snooze_undo" msgid="60890935148417175">"เลิกทำ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0ade0ed7416d..f531de5a89de 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"User"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Bagong user"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Hindi Nakakonekta"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Walang Network"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Naka-off ang Wi-Fi"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Ipakita ang profile"</string>
<string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alisin ang bisita?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alisin"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Maligayang pagbabalik, bisita!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 2608931f296e..ba70531a89f3 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Kullanıcı"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yeni kullanıcı"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Kablosuz"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Bağlı Değil"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ağ yok"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Kablosuz Kapalı"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profili göster"</string>
<string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Misafir oturumu kaldırılsın mı?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kaldır"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tekrar hoş geldiniz sayın misafir!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string>
diff --git a/packages/SystemUI/res/values-tr/strings_tv.xml b/packages/SystemUI/res/values-tr/strings_tv.xml
index babd460a1375..49e76af004ab 100644
--- a/packages/SystemUI/res/values-tr/strings_tv.xml
+++ b/packages/SystemUI/res/values-tr/strings_tv.xml
@@ -23,7 +23,7 @@
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mikrofonunuza erişti"</string>
<string name="notification_vpn_connected" msgid="3891023882833274730">"VPN bağlandı"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN bağlantısı kesildi"</string>
- <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> yoluyla"</string>
+ <string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"<xliff:g id="VPN_APP">%1$s</xliff:g> üzerinden"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Bildirimler"</string>
<string name="tv_notification_panel_no_notifications" msgid="9115191912267270678">"Bildirim Yok"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ce00b92093ef..b2ae569cf26c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -355,6 +355,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Користувач"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Новий користувач"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Не під’єднано."</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Немає мережі"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi вимкнено"</string>
@@ -458,9 +460,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Вийти з режиму гостя?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Вийти"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"З поверненням!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продовжити сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почати знову"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 0032c6bd7c74..06a448b25579 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"صارف"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"نیا صارف"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"مربوط نہیں ہے"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"کوئی نیٹ ورک نہیں ہے"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"‏Wi-Fi آف ہے"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مہمان کو ہٹائیں؟"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ہٹائیں"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 532fa4021131..e1add6503412 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Foydalanuvchi"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Yangi foydalanuvchi"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Ulanmagan"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Tarmoq mavjud emas"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi o‘chiq"</string>
@@ -454,9 +456,9 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Profilni ko‘rsatish"</string>
<string name="user_add_user" msgid="4336657383006913022">"Foydalanuvchi"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Yangi foydalanuvchi"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Mehmon hisobi o‘chirib tashlansinmi?"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="2034481024623462357">"Mehmon seansi yakunlansinmi?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Olib tashlash"</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="8533184512885775423">"Seansni yakunlash"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Xush kelibsiz, mehmon!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Seansni davom ettirmoqchimisiz?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Boshidan boshlansin"</string>
@@ -493,7 +495,7 @@
<string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirishnomalar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha sokin bildirishnomalarni tozalash"</string>
- <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilingan"</string>
+ <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilinadi"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirishnomalar yo‘q"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"Profil kuzatilishi mumkin"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 0e9987732d26..021044d29b34 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Người dùng"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Người dùng mới"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Chưa được kết nối"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Không có mạng nào"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Tắt Wi-Fi"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Hiển thị hồ sơ"</string>
<string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Xóa phiên khách?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Xóa"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 07232ff1119e..60acb839b33a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"用户"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新用户"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"WLAN"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未连接"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"无网络"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"WLAN:关闭"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"要移除访客吗?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7a07af104f07..db55580872f4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網絡"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 關閉"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 0369d6318760..1487ad33d12f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"使用者"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"新使用者"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"未連線"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"沒有網路"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"Wi-Fi 已關閉"</string>
@@ -454,9 +456,11 @@
<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="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 068e2e53f8a1..b0f084b7f83d 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -353,6 +353,8 @@
<string name="quick_settings_user_title" msgid="8673045967216204537">"Umsebenzisi"</string>
<string name="quick_settings_user_new_user" msgid="3347905871336069666">"Umsebenzisi omusha"</string>
<string name="quick_settings_wifi_label" msgid="2879507532983487244">"I-Wi-Fi"</string>
+ <!-- no translation found for quick_settings_internet_label (6603068555872455463) -->
+ <skip />
<string name="quick_settings_wifi_not_connected" msgid="4071097522427039160">"Akuxhunyiwe"</string>
<string name="quick_settings_wifi_no_network" msgid="6003178398713839313">"Ayikho inethiwekhi"</string>
<string name="quick_settings_wifi_off_label" msgid="4003379736176547594">"I-Wi-Fi icimile"</string>
@@ -454,9 +456,11 @@
<string name="accessibility_multi_user_switch_quick_contact" msgid="4504508915324898576">"Bonisa iphrofayela"</string>
<string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string>
- <string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Susa isivakashi?"</string>
+ <!-- no translation found for guest_exit_guest_dialog_title (2034481024623462357) -->
+ <skip />
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
- <string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Susa"</string>
+ <!-- no translation found for guest_exit_guest_dialog_remove (8533184512885775423) -->
+ <skip />
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 323449af0850..6cc863a448c7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,6 +1,7 @@
package com.android.keyguard;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
@@ -107,7 +108,10 @@ public class KeyguardClockSwitch extends RelativeLayout {
/**
* Boolean value indicating if notifications are visible on lock screen.
*/
- private boolean mHasVisibleNotifications;
+ private boolean mHasVisibleNotifications = true;
+
+ private AnimatorSet mClockInAnim = null;
+ private AnimatorSet mClockOutAnim = null;
/**
* If the Keyguard Slice has a header (big center-aligned text.)
@@ -318,12 +322,15 @@ public class KeyguardClockSwitch extends RelativeLayout {
private void animateClockChange(boolean useLargeClock) {
if (mLockScreenMode != KeyguardUpdateMonitor.LOCK_SCREEN_MODE_LAYOUT_1) return;
+ if (mClockInAnim != null) mClockInAnim.cancel();
+ if (mClockOutAnim != null) mClockOutAnim.cancel();
+
View in, out;
int direction = 1;
if (useLargeClock) {
out = mNewLockscreenClockFrame;
in = mNewLockscreenLargeClockFrame;
- addView(in);
+ if (indexOfChild(in) == -1) addView(in);
direction = -1;
} else {
in = mNewLockscreenClockFrame;
@@ -333,25 +340,35 @@ public class KeyguardClockSwitch extends RelativeLayout {
removeView(out);
}
- AnimatorSet outAnim = new AnimatorSet();
- outAnim.setDuration(CLOCK_OUT_MILLIS);
- outAnim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
- outAnim.playTogether(
+ mClockOutAnim = new AnimatorSet();
+ mClockOutAnim.setDuration(CLOCK_OUT_MILLIS);
+ mClockOutAnim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ mClockOutAnim.playTogether(
ObjectAnimator.ofFloat(out, View.ALPHA, 0f),
ObjectAnimator.ofFloat(out, View.TRANSLATION_Y, 0,
direction * -mClockSwitchYAmount));
+ mClockOutAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mClockOutAnim = null;
+ }
+ });
in.setAlpha(0);
in.setVisibility(View.VISIBLE);
- AnimatorSet inAnim = new AnimatorSet();
- inAnim.setDuration(CLOCK_IN_MILLIS);
- inAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- inAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
+ mClockInAnim = new AnimatorSet();
+ mClockInAnim.setDuration(CLOCK_IN_MILLIS);
+ mClockInAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ mClockInAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
ObjectAnimator.ofFloat(in, View.TRANSLATION_Y, direction * mClockSwitchYAmount, 0));
- inAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
+ mClockInAnim.setStartDelay(CLOCK_OUT_MILLIS / 2);
+ mClockInAnim.addListener(new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animation) {
+ mClockInAnim = null;
+ }
+ });
- inAnim.start();
- outAnim.start();
+ mClockInAnim.start();
+ mClockOutAnim.start();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 926062b1623f..f9505dec78fd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -28,9 +28,9 @@ import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index a1bde589d5c1..943a54e61c03 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -22,9 +22,9 @@ import com.android.wm.shell.ShellInit;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.Optional;
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
index 5c1c60c5b07e..80d13715ca07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -29,11 +29,15 @@ import android.provider.Settings
import android.service.media.MediaBrowserService
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.Dumpable
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dump.DumpManager
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.Utils
+import java.io.FileDescriptor
+import java.io.PrintWriter
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -49,8 +53,9 @@ class MediaResumeListener @Inject constructor(
private val broadcastDispatcher: BroadcastDispatcher,
@Background private val backgroundExecutor: Executor,
private val tunerService: TunerService,
- private val mediaBrowserFactory: ResumeMediaBrowserFactory
-) : MediaDataManager.Listener {
+ private val mediaBrowserFactory: ResumeMediaBrowserFactory,
+ dumpManager: DumpManager
+) : MediaDataManager.Listener, Dumpable {
private var useMediaResumption: Boolean = Utils.useMediaResumption(context)
private val resumeComponents: ConcurrentLinkedQueue<ComponentName> = ConcurrentLinkedQueue()
@@ -99,6 +104,7 @@ class MediaResumeListener @Inject constructor(
init {
if (useMediaResumption) {
+ dumpManager.registerDumpable(TAG, this)
val unlockFilter = IntentFilter()
unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
unlockFilter.addAction(Intent.ACTION_USER_SWITCHED)
@@ -283,4 +289,10 @@ class MediaResumeListener @Inject constructor(
mediaBrowser?.restart()
}
}
+
+ override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
+ pw.apply {
+ println("resumeComponents: $resumeComponents")
+ }
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 6d9d587bc729..54e30af675ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -91,11 +91,11 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedEvents;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
new file mode 100644
index 000000000000..143121af9f2c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTile.java
@@ -0,0 +1,113 @@
+/*
+ * 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.screenshot;
+
+import static android.graphics.ColorSpace.Named.SRGB;
+
+import static java.util.Objects.requireNonNull;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.media.Image;
+
+/**
+ * Holds a hardware image, coordinates and render node to draw the tile. The tile manages clipping
+ * and dimensions. The tile must be drawn translated to the correct target position:
+ * <pre>
+ * ImageTile tile = getTile();
+ * canvas.save();
+ * canvas.translate(tile.getLeft(), tile.getTop());
+ * canvas.drawRenderNode(tile.getDisplayList());
+ * canvas.restore();
+ * </pre>
+ */
+class ImageTile implements AutoCloseable {
+ private final Image mImage;
+ private final Rect mLocation;
+ private RenderNode mNode;
+
+ private static final ColorSpace COLOR_SPACE = ColorSpace.get(SRGB);
+
+ /**
+ * Create an image tile from the given image.
+ *
+ * @param image an image containing a hardware buffer
+ * @param location the captured area represented by image tile (virtual coordinates)
+ */
+ ImageTile(Image image, Rect location) {
+ mImage = requireNonNull(image, "image");
+ mLocation = location;
+
+ requireNonNull(mImage.getHardwareBuffer(), "image must be a hardware image");
+ }
+
+ RenderNode getDisplayList() {
+ if (mNode == null) {
+ mNode = new RenderNode("Tile{" + Integer.toHexString(mImage.hashCode()) + "}");
+ }
+ if (mNode.hasDisplayList()) {
+ return mNode;
+ }
+ final int w = Math.min(mImage.getWidth(), mLocation.width());
+ final int h = Math.min(mImage.getHeight(), mLocation.height());
+ mNode.setPosition(0, 0, w, h);
+
+ RecordingCanvas canvas = mNode.beginRecording(w, h);
+ Rect rect = new Rect(0, 0, w, h);
+ canvas.save();
+ canvas.clipRect(0, 0, mLocation.right, mLocation.bottom);
+ canvas.drawBitmap(Bitmap.wrapHardwareBuffer(mImage.getHardwareBuffer(), COLOR_SPACE),
+ 0, 0, null);
+ canvas.restore();
+ mNode.endRecording();
+ return mNode;
+ }
+
+ Rect getLocation() {
+ return mLocation;
+ }
+
+ int getLeft() {
+ return mLocation.left;
+ }
+
+ int getTop() {
+ return mLocation.top;
+ }
+
+ int getRight() {
+ return mLocation.right;
+ }
+
+ int getBottom() {
+ return mLocation.bottom;
+ }
+
+ @Override
+ public void close() {
+ mImage.close();
+ mNode.discardDisplayList();
+ }
+
+ @Override
+ public String toString() {
+ return "{location=" + mLocation + ", source=" + mImage
+ + ", buffer=" + mImage.getHardwareBuffer() + "}";
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
new file mode 100644
index 000000000000..8ff66f548172
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
@@ -0,0 +1,163 @@
+/*
+ * 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.screenshot;
+
+import android.graphics.Bitmap;
+import android.graphics.HardwareRenderer;
+import android.graphics.RecordingCanvas;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.graphics.drawable.Drawable;
+
+import androidx.annotation.UiThread;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Owns a series of partial screen captures (tiles).
+ * <p>
+ * To display on-screen, use {@link #getDrawable()}.
+ */
+@UiThread
+class ImageTileSet {
+
+ private static final String TAG = "ImageTileSet";
+
+ interface OnBoundsChangedListener {
+ /**
+ * Reports an update to the bounding box that contains all active tiles. These are virtual
+ * (capture) coordinates which can be either negative or positive.
+ */
+ void onBoundsChanged(int left, int top, int right, int bottom);
+ }
+
+ interface OnContentChangedListener {
+ /**
+ * Mark as dirty and rebuild display list.
+ */
+ void onContentChanged();
+ }
+
+ private final List<ImageTile> mTiles = new ArrayList<>();
+ private final Rect mBounds = new Rect();
+
+ private OnContentChangedListener mOnContentChangedListener;
+ private OnBoundsChangedListener mOnBoundsChangedListener;
+
+ void setOnBoundsChangedListener(OnBoundsChangedListener listener) {
+ mOnBoundsChangedListener = listener;
+ }
+
+ void setOnContentChangedListener(OnContentChangedListener listener) {
+ mOnContentChangedListener = listener;
+ }
+
+ void addTile(ImageTile tile) {
+ final Rect newBounds = new Rect(mBounds);
+ final Rect newRect = tile.getLocation();
+ mTiles.add(tile);
+ newBounds.union(newRect);
+ if (!newBounds.equals(mBounds)) {
+ mBounds.set(newBounds);
+ if (mOnBoundsChangedListener != null) {
+ mOnBoundsChangedListener.onBoundsChanged(
+ newBounds.left, newBounds.top, newBounds.right, newBounds.bottom);
+ }
+ }
+ if (mOnContentChangedListener != null) {
+ mOnContentChangedListener.onContentChanged();
+ }
+ }
+
+ /**
+ * Returns a drawable to paint the combined contents of the tiles. Drawable dimensions are
+ * zero-based and map directly to {@link #getLeft()}, {@link #getTop()}, {@link #getRight()},
+ * and {@link #getBottom()} which are dimensions relative to the capture start position
+ * (positive or negative).
+ *
+ * @return a drawable to display the image content
+ */
+ Drawable getDrawable() {
+ return new TiledImageDrawable(this);
+ }
+
+ boolean isEmpty() {
+ return mTiles.isEmpty();
+ }
+
+ int size() {
+ return mTiles.size();
+ }
+
+ ImageTile get(int i) {
+ return mTiles.get(i);
+ }
+
+ Bitmap toBitmap() {
+ if (mTiles.isEmpty()) {
+ return null;
+ }
+ final RenderNode output = new RenderNode("Bitmap Export");
+ output.setPosition(0, 0, getWidth(), getHeight());
+ RecordingCanvas canvas = output.beginRecording();
+ canvas.translate(-getLeft(), -getTop());
+ for (ImageTile tile : mTiles) {
+ canvas.save();
+ canvas.translate(tile.getLeft(), tile.getTop());
+ canvas.drawRenderNode(tile.getDisplayList());
+ canvas.restore();
+ }
+ output.endRecording();
+ return HardwareRenderer.createHardwareBitmap(output, getWidth(), getHeight());
+ }
+
+ int getLeft() {
+ return mBounds.left;
+ }
+
+ int getTop() {
+ return mBounds.top;
+ }
+
+ int getRight() {
+ return mBounds.right;
+ }
+
+ int getBottom() {
+ return mBounds.bottom;
+ }
+
+ int getWidth() {
+ return mBounds.width();
+ }
+
+ int getHeight() {
+ return mBounds.height();
+ }
+
+ void clear() {
+ mBounds.set(0, 0, 0, 0);
+ mTiles.forEach(ImageTile::close);
+ mTiles.clear();
+ if (mOnBoundsChangedListener != null) {
+ mOnBoundsChangedListener.onBoundsChanged(0, 0, 0, 0);
+ }
+ if (mOnContentChangedListener != null) {
+ mOnContentChangedListener.onContentChanged();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index e159992bc9a5..bb07012f2355 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -18,6 +18,7 @@ package com.android.systemui.screenshot;
import static com.android.systemui.screenshot.LogConfig.DEBUG_SCROLL;
+import static java.lang.Math.min;
import static java.util.Objects.requireNonNull;
import android.annotation.UiContext;
@@ -44,15 +45,20 @@ import java.util.function.Consumer;
import javax.inject.Inject;
/**
- * High level interface to scroll capture API.
+ * High(er) level interface to scroll capture API.
*/
public class ScrollCaptureClient {
+ private static final int TILE_SIZE_PX_MAX = 4 * (1024 * 1024);
+ private static final int TILES_PER_PAGE = 2; // increase once b/174571735 is addressed
+ private static final int MAX_PAGES = 5;
+ private static final int MAX_IMAGE_COUNT = MAX_PAGES * TILES_PER_PAGE;
@VisibleForTesting
static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
private static final String TAG = LogConfig.logTag(ScrollCaptureClient.class);
+
/**
* A connection to a remote window. Starts a capture session.
*/
@@ -60,13 +66,10 @@ public class ScrollCaptureClient {
/**
* Session start should be deferred until UI is active because of resource allocation and
* potential visible side effects in the target window.
- *
- * @param maxBuffers the maximum number of buffers (tiles) that may be in use at one
- * time, tiles are not cached anywhere so set this to a large enough
- * number to retain offscreen content until it is no longer needed
+
* @param sessionConsumer listener to receive the session once active
*/
- void start(int maxBuffers, Consumer<Session> sessionConsumer);
+ void start(Consumer<Session> sessionConsumer);
/**
* Close the connection.
@@ -100,26 +103,33 @@ public class ScrollCaptureClient {
*/
interface Session {
/**
- * Request the given horizontal strip. Values are y-coordinates in captured space, relative
- * to start position.
+ * Request an image tile at the given position, from top, to top + {@link #getTileHeight()},
+ * and from left 0, to {@link #getPageWidth()}
*
- * @param contentRect the area to capture, in content rect space, relative to scroll-bounds
+ * @param top the top (y) position of the tile to capture, in content rect space
* @param consumer listener to be informed of the result
*/
- void requestTile(Rect contentRect, Consumer<CaptureResult> consumer);
+ void requestTile(int top, Consumer<CaptureResult> consumer);
/**
- * End the capture session, return the target app to original state. The returned
- * stage must be waited for to complete to allow the target app a chance to restore to
- * original state before becoming visible.
+ * Returns the maximum number of tiles which may be requested and retained without
+ * being {@link Image#close() closed}.
*
- * @return a stage presenting the session shutdown
+ * @return the maximum number of open tiles allowed
*/
- void end(Runnable listener);
+ int getMaxTiles();
+
+ int getTileHeight();
+
+ int getPageHeight();
- int getMaxTileHeight();
+ int getPageWidth();
- int getMaxTileWidth();
+ /**
+ * End the capture session, return the target app to original state. The listener
+ * will be called when the target app is ready to before visible and interactive.
+ */
+ void end(Runnable listener);
}
private final IWindowManager mWindowManagerService;
@@ -131,6 +141,12 @@ public class ScrollCaptureClient {
mWindowManagerService = windowManagerService;
}
+ /**
+ * Set the window token for the screenshot window/ This is required to avoid targeting our
+ * window or any above it.
+ *
+ * @param token the windowToken of the screenshot window
+ */
public void setHostWindowToken(IBinder token) {
mHostWindowToken = token;
}
@@ -176,6 +192,8 @@ public class ScrollCaptureClient {
private ImageReader mReader;
private Rect mScrollBounds;
+ private int mTileHeight;
+ private int mTileWidth;
private Rect mRequestRect;
private boolean mStarted;
@@ -197,6 +215,15 @@ public class ScrollCaptureClient {
mScrollBounds = scrollBounds;
mConnectionConsumer.accept(this);
mConnectionConsumer = null;
+
+ int pxPerPage = mScrollBounds.width() * mScrollBounds.height();
+ int pxPerTile = min(TILE_SIZE_PX_MAX, (pxPerPage / TILES_PER_PAGE));
+ mTileWidth = mScrollBounds.width();
+ mTileHeight = pxPerTile / mScrollBounds.width();
+ if (DEBUG_SCROLL) {
+ Log.d(TAG, "scrollBounds: " + mScrollBounds);
+ Log.d(TAG, "tile dimen: " + mTileWidth + "x" + mTileHeight);
+ }
}
@Override
@@ -257,24 +284,19 @@ public class ScrollCaptureClient {
// ScrollCaptureController.Connection
- // -> Error handling: BiConsumer<Session, Throwable> ?
@Override
- public void start(int maxBufferCount, Consumer<Session> sessionConsumer) {
+ public void start(Consumer<Session> sessionConsumer) {
if (DEBUG_SCROLL) {
- Log.d(TAG, "start(maxBufferCount=" + maxBufferCount
- + ", sessionConsumer=" + sessionConsumer + ")");
+ Log.d(TAG, "start(sessionConsumer=" + sessionConsumer + ")");
}
- mReader = ImageReader.newInstance(mScrollBounds.width(), mScrollBounds.height(),
- PixelFormat.RGBA_8888, maxBufferCount, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
+ MAX_IMAGE_COUNT, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mSessionConsumer = sessionConsumer;
try {
mConnection.startCapture(mReader.getSurface());
mStarted = true;
} catch (RemoteException e) {
- Log.w(TAG, "should not be happening :-(");
- // ?
- //mSessionListener.onError(e);
- //mSessionListener = null;
+ Log.w(TAG, "Failed to start", e);
}
}
@@ -307,27 +329,36 @@ public class ScrollCaptureClient {
}
@Override
- public int getMaxTileHeight() {
+ public int getPageHeight() {
return mScrollBounds.height();
}
@Override
- public int getMaxTileWidth() {
+ public int getPageWidth() {
return mScrollBounds.width();
}
@Override
- public void requestTile(Rect contentRect, Consumer<CaptureResult> consumer) {
+ public int getTileHeight() {
+ return mTileHeight;
+ }
+
+ @Override
+ public int getMaxTiles() {
+ return MAX_IMAGE_COUNT;
+ }
+
+ @Override
+ public void requestTile(int top, Consumer<CaptureResult> consumer) {
if (DEBUG_SCROLL) {
- Log.d(TAG, "requestTile(contentRect=" + contentRect + "consumer=" + consumer + ")");
+ Log.d(TAG, "requestTile(top=" + top + ", consumer=" + consumer + ")");
}
- mRequestRect = new Rect(contentRect);
+ mRequestRect = new Rect(0, top, mTileWidth, top + mTileHeight);
mResultConsumer = consumer;
try {
mConnection.requestImage(mRequestRect);
} catch (RemoteException e) {
Log.e(TAG, "Caught remote exception from requestImage", e);
- // ?
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 27c74ac0938d..c75efbcc5f80 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -16,16 +16,9 @@
package com.android.systemui.screenshot;
-import static android.graphics.ColorSpace.Named.SRGB;
-
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorSpace;
-import android.graphics.Picture;
-import android.graphics.Rect;
-import android.media.Image;
import android.net.Uri;
import android.os.UserHandle;
import android.util.Log;
@@ -46,6 +39,8 @@ import java.util.function.Consumer;
public class ScrollCaptureController {
private static final String TAG = "ScrollCaptureController";
+ private static final boolean USE_TILED_IMAGE = false;
+
public static final int MAX_PAGES = 5;
public static final int MAX_HEIGHT = 12000;
@@ -55,7 +50,7 @@ public class ScrollCaptureController {
private final Executor mUiExecutor;
private final Executor mBgExecutor;
private final ImageExporter mImageExporter;
- private Picture mPicture;
+ private final ImageTileSet mImageTileSet;
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
Executor bgExecutor, ImageExporter exporter) {
@@ -64,6 +59,7 @@ public class ScrollCaptureController {
mUiExecutor = uiExecutor;
mBgExecutor = bgExecutor;
mImageExporter = exporter;
+ mImageTileSet = new ImageTileSet();
}
/**
@@ -72,50 +68,50 @@ public class ScrollCaptureController {
* @param after action to take after the flow is complete
*/
public void run(final Runnable after) {
- mConnection.start(MAX_PAGES, (session) -> startCapture(session, after));
+ mConnection.start((session) -> startCapture(session, after));
}
private void startCapture(Session session, final Runnable onDismiss) {
- Rect requestRect = new Rect(0, 0,
- session.getMaxTileWidth(), session.getMaxTileHeight());
Consumer<ScrollCaptureClient.CaptureResult> consumer =
new Consumer<ScrollCaptureClient.CaptureResult>() {
int mFrameCount = 0;
+ int mTop = 0;
@Override
public void accept(ScrollCaptureClient.CaptureResult result) {
mFrameCount++;
+
boolean emptyFrame = result.captured.height() == 0;
if (!emptyFrame) {
- mPicture = stackBelow(mPicture, result.image, result.captured.width(),
- result.captured.height());
+ mImageTileSet.addTile(new ImageTile(result.image, result.captured));
}
+
if (emptyFrame || mFrameCount >= MAX_PAGES
- || requestRect.bottom > MAX_HEIGHT) {
- if (mPicture != null) {
- exportToFile(mPicture, session, onDismiss);
+ || mTop + session.getTileHeight() > MAX_HEIGHT) {
+ if (!mImageTileSet.isEmpty()) {
+ exportToFile(mImageTileSet.toBitmap(), session, onDismiss);
+ mImageTileSet.clear();
} else {
session.end(onDismiss);
}
return;
}
- requestRect.offset(0, session.getMaxTileHeight());
- session.requestTile(requestRect, /* consumer */ this);
+ mTop += result.captured.height();
+ session.requestTile(mTop, /* consumer */ this);
}
};
// fire it up!
- session.requestTile(requestRect, consumer);
+ session.requestTile(0, consumer);
};
- void exportToFile(Picture picture, Session session, Runnable afterEnd) {
+ void exportToFile(Bitmap bitmap, Session session, Runnable afterEnd) {
mImageExporter.setFormat(Bitmap.CompressFormat.PNG);
mImageExporter.setQuality(6);
ListenableFuture<Uri> future =
- mImageExporter.export(mBgExecutor, Bitmap.createBitmap(picture));
+ mImageExporter.export(mBgExecutor, bitmap);
future.addListener(() -> {
- picture.close(); // release resources
try {
launchViewer(future.get());
} catch (InterruptedException | ExecutionException e) {
@@ -126,41 +122,6 @@ public class ScrollCaptureController {
}, mUiExecutor);
}
- /**
- * Combine the top {@link Picture} with an {@link Image} by appending the image directly
- * below, creating a result that is the combined height of both.
- * <p>
- * Note: no pixel data is transferred here, only a record of drawing commands. Backing
- * hardware buffers must not be modified/recycled until the picture is
- * {@link Picture#close closed}.
- *
- * @param top the existing picture
- * @param below the image to append below
- * @param cropWidth the width of the pixel data to use from the image
- * @param cropHeight the height of the pixel data to use from the image
- *
- * @return a new Picture which draws the previous picture with the image below it
- */
- private static Picture stackBelow(Picture top, Image below, int cropWidth, int cropHeight) {
- int width = cropWidth;
- int height = cropHeight;
- if (top != null) {
- height += top.getHeight();
- width = Math.max(width, top.getWidth());
- }
- Picture combined = new Picture();
- Canvas canvas = combined.beginRecording(width, height);
- int y = 0;
- if (top != null) {
- canvas.drawPicture(top, new Rect(0, 0, top.getWidth(), top.getHeight()));
- y += top.getHeight();
- }
- canvas.drawBitmap(Bitmap.wrapHardwareBuffer(
- below.getHardwareBuffer(), ColorSpace.get(SRGB)), 0, y, null);
- combined.endRecording();
- return combined;
- }
-
void launchViewer(Uri uri) {
Intent editIntent = new Intent(Intent.ACTION_VIEW);
editIntent.setType("image/png");
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
new file mode 100644
index 000000000000..72f489bdd398
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TiledImageDrawable.java
@@ -0,0 +1,117 @@
+/*
+ * 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.screenshot;
+
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RenderNode;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+/**
+ * Draws a set of hardware image tiles from a display list. The tiles exist in virtual coordinate
+ * space that may extend into positive or negative values. The origin is the upper-left-most corner
+ * of bounding box, which is drawn at 0,0 to the drawable (output) bounds.
+ */
+public class TiledImageDrawable extends Drawable {
+
+ private static final String TAG = "TiledImageDrawable";
+
+ private final ImageTileSet mTiles;
+ private RenderNode mNode;
+
+ public TiledImageDrawable(ImageTileSet tiles) {
+ mTiles = tiles;
+ mTiles.setOnContentChangedListener(this::onContentChanged);
+ }
+
+ private void onContentChanged() {
+ if (mNode != null && mNode.hasDisplayList()) {
+ mNode.discardDisplayList();
+ }
+ invalidateSelf();
+ }
+
+ private void rebuildDisplayListIfNeeded() {
+ if (mNode != null && mNode.hasDisplayList()) {
+ return;
+ }
+ if (mNode == null) {
+ mNode = new RenderNode("TiledImageDrawable");
+ }
+ mNode.setPosition(0, 0, mTiles.getWidth(), mTiles.getHeight());
+ Canvas canvas = mNode.beginRecording(mTiles.getWidth(), mTiles.getHeight());
+ // Align content (virtual) top/left with 0,0, within the render node
+ canvas.translate(-mTiles.getLeft(), -mTiles.getTop());
+ for (int i = 0; i < mTiles.size(); i++) {
+ ImageTile tile = mTiles.get(i);
+ canvas.save();
+ canvas.translate(tile.getLeft(), tile.getTop());
+ canvas.drawRenderNode(tile.getDisplayList());
+ canvas.restore();
+ }
+ mNode.endRecording();
+ }
+
+ /**
+ * Draws the tiled image to the canvas, with the top/left (virtual) coordinate aligned to 0,0
+ * placed at left/top of the drawable's bounds.
+ */
+ @Override
+ public void draw(Canvas canvas) {
+ rebuildDisplayListIfNeeded();
+ if (canvas.isHardwareAccelerated()) {
+ Rect bounds = getBounds();
+ canvas.save();
+ canvas.clipRect(bounds);
+ canvas.translate(bounds.left, bounds.top);
+ canvas.drawRenderNode(mNode);
+ canvas.restore();
+ } else {
+ Log.d(TAG, "Canvas is not hardware accelerated. Skipping draw!");
+ }
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mTiles.getWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mTiles.getHeight();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ if (mNode.setAlpha(alpha / 255f)) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ throw new IllegalArgumentException("not implemented");
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
index dbee0ee8f5d5..9ef304d7e83c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java
@@ -20,6 +20,8 @@ import android.app.Notification;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
@@ -456,12 +458,14 @@ public class NotificationGroupingUtil {
if (target == null) {
return;
}
- Integer value = (Integer) target.getTag(iconVisible
+ final Integer data = (Integer) target.getTag(iconVisible
? com.android.internal.R.id.tag_margin_end_when_icon_visible
: com.android.internal.R.id.tag_margin_end_when_icon_gone);
- if (value == null) {
+ if (data == null) {
return;
}
+ final DisplayMetrics metrics = target.getResources().getDisplayMetrics();
+ final int value = TypedValue.complexToDimensionPixelOffset(data, metrics);
if (target instanceof NotificationHeaderView) {
((NotificationHeaderView) target).setTopLineExtraMarginEnd(value);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
index 125b5d4c7b8d..4d3af9c01153 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java
@@ -24,6 +24,7 @@ import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -32,11 +33,8 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.tv.PipController;
-import com.android.wm.shell.pip.tv.PipControlsView;
-import com.android.wm.shell.pip.tv.PipControlsViewController;
import com.android.wm.shell.pip.tv.PipNotification;
import com.android.wm.shell.pip.tv.TvPipMenuController;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import java.util.Optional;
@@ -75,19 +73,6 @@ public abstract class TvPipModule {
@WMSingleton
@Provides
- static PipControlsViewController providePipControlsViewController(
- PipControlsView pipControlsView, PipController pipController) {
- return new PipControlsViewController(pipControlsView, pipController);
- }
-
- @WMSingleton
- @Provides
- static PipControlsView providePipControlsView(Context context) {
- return new PipControlsView(context, null);
- }
-
- @WMSingleton
- @Provides
static PipNotification providePipNotification(Context context,
PipMediaController pipMediaController) {
return new PipNotification(context, pipMediaController);
@@ -108,9 +93,12 @@ public abstract class TvPipModule {
@WMSingleton
@Provides
- static TvPipMenuController providesPipTvMenuController(Context context,
- PipBoundsState pipBoundsState, SystemWindows systemWindows) {
- return new TvPipMenuController(context, pipBoundsState, systemWindows);
+ static TvPipMenuController providesPipTvMenuController(
+ Context context,
+ PipBoundsState pipBoundsState,
+ SystemWindows systemWindows,
+ PipMediaController pipMediaController) {
+ return new TvPipMenuController(context, pipBoundsState, systemWindows, pipMediaController);
}
@WMSingleton
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
index 765fd32f7cd2..1049548c382c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvWMShellModule.java
@@ -23,6 +23,7 @@ import android.view.IWindowManager;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.Transitions;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -58,9 +59,10 @@ public class TvWMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener,
+ Transitions transitions) {
return new LegacySplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
- taskStackListener);
+ taskStackListener, transitions);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 3399a0bfc72e..9ec7657c5dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -23,6 +23,7 @@ import android.view.IWindowManager;
import com.android.systemui.dagger.WMSingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.Transitions;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.apppairs.AppPairs;
import com.android.wm.shell.apppairs.AppPairsController;
@@ -35,6 +36,8 @@ import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsAlgorithm;
import com.android.wm.shell.pip.PipBoundsState;
@@ -46,8 +49,6 @@ import com.android.wm.shell.pip.phone.PhonePipMenuController;
import com.android.wm.shell.pip.phone.PipAppOpsListener;
import com.android.wm.shell.pip.phone.PipController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -76,10 +77,11 @@ public class WMShellModule {
DisplayController displayController, SystemWindows systemWindows,
DisplayImeController displayImeController, @Main Handler handler,
TransactionPool transactionPool, ShellTaskOrganizer shellTaskOrganizer,
- SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener) {
+ SyncTransactionQueue syncQueue, TaskStackListenerImpl taskStackListener,
+ Transitions transitions) {
return new LegacySplitScreenController(context, displayController, systemWindows,
displayImeController, handler, transactionPool, shellTaskOrganizer, syncQueue,
- taskStackListener);
+ taskStackListener, transitions);
}
@WMSingleton
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
index 5d81de6bce00..59c2b176f12e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
@@ -33,6 +33,7 @@ import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dump.DumpManager
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
@@ -85,6 +86,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
@Mock private lateinit var sharedPrefsEditor: SharedPreferences.Editor
@Mock private lateinit var mockContext: Context
@Mock private lateinit var pendingIntent: PendingIntent
+ @Mock private lateinit var dumpManager: DumpManager
@Captor lateinit var callbackCaptor: ArgumentCaptor<ResumeMediaBrowser.Callback>
@@ -120,7 +122,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
executor = FakeExecutor(FakeSystemClock())
resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
- tunerService, resumeBrowserFactory)
+ tunerService, resumeBrowserFactory, dumpManager)
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -159,7 +161,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
// When listener is created, we do NOT register a user change listener
val listener = MediaResumeListener(context, broadcastDispatcher, executor, tunerService,
- resumeBrowserFactory)
+ resumeBrowserFactory, dumpManager)
listener.setManager(mediaDataManager)
verify(broadcastDispatcher, never()).registerReceiver(eq(listener.userChangeReceiver),
any(), any(), any())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
index b3176ddeaf65..4d32a3b4077f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java
@@ -40,8 +40,8 @@ import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
+import com.android.wm.shell.pip.Pip;
import org.junit.Before;
import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
index 4aa730efa91e..c1c637129d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureClientTest.java
@@ -96,13 +96,13 @@ public class ScrollCaptureClientTest extends SysuiTestCase {
Connection conn = mConnectionConsumer.getValue();
- conn.start(5, mSessionConsumer);
+ conn.start(mSessionConsumer);
verify(mSessionConsumer, timeout(100)).accept(any(Session.class));
Session session = mSessionConsumer.getValue();
- Rect request = new Rect(0, 0, session.getMaxTileWidth(), session.getMaxTileHeight());
+ Rect request = new Rect(0, 0, session.getPageWidth(), session.getTileHeight());
- session.requestTile(request, mResultConsumer);
+ session.requestTile(0, mResultConsumer);
verify(mResultConsumer, timeout(100)).accept(any(CaptureResult.class));
CaptureResult result = mResultConsumer.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index 73d87b0d4596..31bf7120900f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -35,12 +35,12 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tracing.ProtoTracer;
import com.android.wm.shell.ShellCommandHandler;
import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
+import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.onehanded.OneHandedGestureHandler;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index ea1ac0c3fddc..2906ceebca58 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -839,14 +839,22 @@ public abstract class IntentResolver<F, R extends Object> {
}
};
- // Make <this> a copy of <orig>. The presumption is that <this> is empty.
- protected void doCopy(IntentResolver orig) {
+ // Make <this> a copy of <orig>. The presumption is that <this> is empty but all
+ // arrays are cleared out explicitly, just to be sure.
+ protected void copyFrom(IntentResolver orig) {
+ mFilters.clear();
mFilters.addAll(orig.mFilters);
+ mTypeToFilter.clear();
mTypeToFilter.putAll(orig.mTypeToFilter);
+ mBaseTypeToFilter.clear();
mBaseTypeToFilter.putAll(orig.mBaseTypeToFilter);
+ mWildTypeToFilter.clear();
mWildTypeToFilter.putAll(orig.mWildTypeToFilter);
+ mSchemeToFilter.clear();
mSchemeToFilter.putAll(orig.mSchemeToFilter);
+ mActionToFilter.clear();
mActionToFilter.putAll(orig.mActionToFilter);
+ mTypedActionToFilter.clear();
mTypedActionToFilter.putAll(orig.mTypedActionToFilter);
}
diff --git a/services/core/java/com/android/server/utils/WatchableIntentResolver.java b/services/core/java/com/android/server/WatchableIntentResolver.java
index 767fc07d8cad..2ef94f17e5d9 100644
--- a/services/core/java/com/android/server/utils/WatchableIntentResolver.java
+++ b/services/core/java/com/android/server/WatchableIntentResolver.java
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-package com.android.server.utils;
+package com.android.server;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.server.IntentResolver;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watcher;
import java.util.List;
@@ -37,28 +39,45 @@ public abstract class WatchableIntentResolver<F, R extends Object>
* Watchable machinery
*/
private final Watchable mWatchable = new WatchableImpl();
+
/**
* Register an observer to receive change notifications.
* @param observer The observer to register.
*/
+ @Override
public void registerObserver(@NonNull Watcher observer) {
mWatchable.registerObserver(observer);
}
+
/**
* Unregister the observer, which will no longer receive change notifications.
* @param observer The observer to unregister.
*/
+ @Override
public void unregisterObserver(@NonNull Watcher observer) {
mWatchable.unregisterObserver(observer);
}
+
+ /**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
+
/**
* Notify listeners that the object has changd. The argument is a hint as to the
* source of the change.
* @param what The attribute or sub-object that changed, if not null.
*/
+ @Override
public void dispatchChange(@Nullable Watchable what) {
mWatchable.dispatchChange(what);
}
+
/**
* Notify listeners that this object has changed.
*/
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 15e31ba0f140..117098315ef7 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4756,7 +4756,7 @@ public class AccountManagerService
IAccountManagerResponse getResponseAndClose() {
if (mResponse == null) {
- // this session has already been closed
+ close();
return null;
}
IAccountManagerResponse response = mResponse;
diff --git a/services/core/java/com/android/server/apphibernation/OWNERS b/services/core/java/com/android/server/apphibernation/OWNERS
new file mode 100644
index 000000000000..4804fa3eb915
--- /dev/null
+++ b/services/core/java/com/android/server/apphibernation/OWNERS
@@ -0,0 +1,3 @@
+# TODO: Include /core/java/android/apphibernation/OWNERS. See b/177005153
+kevhan@google.com
+rajekumar@google.com
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 9898d7676178..493c68862567 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -56,9 +56,9 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
public AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality,
- int statsAction, int statsClient) {
+ int statsAction, int statsClient, boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
- statsAction, statsClient);
+ statsAction, statsClient, shouldLogMetrics);
mPowerManager = context.getSystemService(PowerManager.class);
mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 0943c9ca17fe..52923283f22c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.content.ComponentName;
import android.content.Context;
@@ -67,7 +66,8 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
- statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+ statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
+ true /* shouldLogMetrics */);
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
index bbd652357888..27c2dd069dce 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -105,8 +105,8 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
public ClientMonitor(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
- int statsClient) {
- super(statsModality, statsAction, statsClient);
+ int statsClient, boolean shouldLogMetrics) {
+ super(statsModality, statsAction, statsClient, shouldLogMetrics);
mSequentialId = sCount++;
mContext = context;
mLazyDaemon = lazyDaemon;
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index 8bf9680d60cd..fbe3d8469d81 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -49,10 +49,10 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int statsModality, int sensorId,
- boolean shouldVibrate) {
+ boolean shouldVibrate, boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
statsModality, BiometricsProtoEnums.ACTION_ENROLL,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, shouldLogMetrics);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
diff --git a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
index bac944fca1de..f6a1040f6a7b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/GenerateChallengeClient.java
@@ -32,7 +32,7 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
@NonNull String owner, int sensorId) {
super(context, lazyDaemon, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index e738d17f5f17..e56e116f6e1d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -107,7 +107,8 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* ClientMonitorCallbackConverter */,
userId, owner, 0 /* cookie */, sensorId, statsModality,
- BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList;
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
index e07f71298d13..158b836c84cd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalEnumerateClient.java
@@ -51,7 +51,7 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
// is all done internally.
super(context, lazyDaemon, token, null /* ClientMonitorCallbackConverter */, userId, owner,
0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
mEnrolledList = enrolledList;
mUtils = utils;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
index d85ab25cc812..59e40da47578 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -38,6 +38,7 @@ public abstract class LoggableMonitor {
private final int mStatsAction;
private final int mStatsClient;
private long mFirstAcquireTimeMs;
+ private boolean mShouldLogMetrics;
/**
* Only valid for AuthenticationClient.
@@ -51,11 +52,14 @@ public abstract class LoggableMonitor {
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
+ * @param shouldLogMetrics If set to false, metrics will not be reported to statsd.
*/
- public LoggableMonitor(int statsModality, int statsAction, int statsClient) {
+ public LoggableMonitor(int statsModality, int statsAction, int statsClient,
+ boolean shouldLogMetrics) {
mStatsModality = statsModality;
mStatsAction = statsAction;
mStatsClient = statsClient;
+ mShouldLogMetrics = shouldLogMetrics;
}
public int getStatsClient() {
@@ -70,6 +74,9 @@ public abstract class LoggableMonitor {
protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode,
int targetUserId) {
+ if (!mShouldLogMetrics) {
+ return;
+ }
final boolean isFace = mStatsModality == BiometricsProtoEnums.MODALITY_FACE;
final boolean isFingerprint = mStatsModality == BiometricsProtoEnums.MODALITY_FINGERPRINT;
@@ -110,6 +117,10 @@ public abstract class LoggableMonitor {
protected final void logOnError(Context context, int error, int vendorCode, int targetUserId) {
+ if (!mShouldLogMetrics) {
+ return;
+ }
+
final long latency = mFirstAcquireTimeMs != 0
? (System.currentTimeMillis() - mFirstAcquireTimeMs) : -1;
@@ -144,6 +155,10 @@ public abstract class LoggableMonitor {
protected final void logOnAuthenticated(Context context, boolean authenticated,
boolean requireConfirmation, int targetUserId, boolean isBiometricPrompt) {
+ if (!mShouldLogMetrics) {
+ return;
+ }
+
int authState = FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__UNKNOWN;
if (!authenticated) {
authState = FrameworkStatsLog.BIOMETRIC_AUTHENTICATED__STATE__REJECTED;
@@ -189,6 +204,10 @@ public abstract class LoggableMonitor {
}
protected final void logOnEnrolled(int targetUserId, long latency, boolean enrollSuccessful) {
+ if (!mShouldLogMetrics) {
+ return;
+ }
+
if (DEBUG) {
Slog.v(TAG, "Enrolled! Modality: " + mStatsModality
+ ", User: " + targetUserId
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index f79abd59dbb4..22b57170e494 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -45,7 +45,7 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
int sensorId, @NonNull Map<Integer, Long> authenticatorIds, int statsModality) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
statsModality, BiometricsProtoEnums.ACTION_REMOVE,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
mBiometricId = biometricId;
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
diff --git a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
index 5deb8fa26639..dcbd4b5d7768 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RevokeChallengeClient.java
@@ -27,7 +27,8 @@ public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
@NonNull IBinder token, @NonNull String owner, int sensorId) {
super(context, lazyDaemon, token, null /* listener */, 0 /* userId */, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index f09df1e1812e..99b89e365b99 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -62,7 +62,7 @@ public class FaceEnrollClient extends EnrollClient<ISession> {
@Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
- false /* shouldVibrate */);
+ false /* shouldVibrate */, true /* shouldLogMetrics */);
mEnrollIgnoreList = getContext().getResources()
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
mEnrollIgnoreListVendor = getContext().getResources()
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
index c27b6e5a4b7d..ce0bb4566ea3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceGetAuthenticatorIdClient.java
@@ -38,7 +38,8 @@ class FaceGetAuthenticatorIdClient extends ClientMonitor<ISession> {
Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FACE,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mAuthenticatorIds = authenticatorIds;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
index 5b1f5465ea0a..500099522d0b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceResetLockoutClient.java
@@ -50,7 +50,8 @@ public class FaceResetLockoutClient extends ClientMonitor<ISession> {
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 1a7544fc7f01..bc1eace3c9f7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -59,7 +59,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
@Nullable NativeHandle surfaceHandle, int sensorId) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
- false /* shouldVibrate */);
+ false /* shouldVibrate */, true /* shouldLogMetrics */);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mSurfaceHandle = surfaceHandle;
mEnrollIgnoreList = getContext().getResources()
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
index e25bb812caa6..3758774e8d13 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceGetFeatureClient.java
@@ -47,7 +47,7 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
@NonNull String owner, int sensorId, int feature, int faceId) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
mFeature = feature;
mFaceId = faceId;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
index 8df9b9f305de..06808e0c30da 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceResetLockoutClient.java
@@ -42,7 +42,8 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
@NonNull byte[] hardwareAuthToken) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mHardwareAuthToken = new ArrayList<>();
for (byte b : hardwareAuthToken) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
index 0e2072823684..b2db6c7d24bc 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceSetFeatureClient.java
@@ -49,7 +49,7 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
byte[] hardwareAuthToken, int faceId) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
- BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
mFeature = feature;
mEnabled = enabled;
mFaceId = faceId;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 22275e5f9d32..c9d2cd378c3a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -43,7 +43,8 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mCurrentUserId = currentUserId;
mHasEnrolledBiometrics = hasEnrolledBIometrics;
mAuthenticatorIds = authenticatorIds;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 61f9cc40d233..e6cdbd28f9d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -66,10 +66,10 @@ import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.BiometricServiceCallback;
import com.android.server.biometrics.sensors.fingerprint.aidl.FingerprintProvider;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21;
import com.android.server.biometrics.sensors.fingerprint.hidl.Fingerprint21UdfpsMock;
@@ -188,7 +188,8 @@ public class FingerprintService extends SystemService implements BiometricServic
@Override // Binder call
public void enroll(final IBinder token, final byte[] hardwareAuthToken, final int userId,
- final IFingerprintServiceReceiver receiver, final String opPackageName) {
+ final IFingerprintServiceReceiver receiver, final String opPackageName,
+ boolean shouldLogMetrics) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -198,7 +199,7 @@ public class FingerprintService extends SystemService implements BiometricServic
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName);
+ receiver, opPackageName, shouldLogMetrics);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 6e36cd24b2e7..d94c98481eeb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -76,7 +76,8 @@ public interface ServiceProvider {
@NonNull String opPackageName, long challenge);
void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
- @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName);
+ @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
+ boolean shouldLogMetrics);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 3f9aef2b8651..e95447b49872 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -121,7 +121,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), true /* shouldLogMetrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index 339832373b74..483ca5ddec3f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -51,7 +51,7 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
- statsClient);
+ statsClient, true /* shouldLogMetrics */);
mIsStrongBiometric = isStrongBiometric;
mUdfpsOverlayController = udfpsOverlayController;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
index 3e13c45d335e..b4f705405fa9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java
@@ -51,10 +51,11 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
- @Nullable IUdfpsOverlayController udfpsOvelayController, int maxTemplatesPerUser) {
+ @Nullable IUdfpsOverlayController udfpsOvelayController, int maxTemplatesPerUser,
+ boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
- true /* shouldVibrate */);
+ true /* shouldVibrate */, shouldLogMetrics);
mUdfpsOverlayController = udfpsOvelayController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
index 2ad1fa306781..b30cc1a5f50a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintGetAuthenticatorIdClient.java
@@ -38,7 +38,8 @@ class FingerprintGetAuthenticatorIdClient extends ClientMonitor<ISession> {
int sensorId, Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FINGERPRINT,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mAuthenticatorIds = authenticatorIds;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 99c662a57c3b..a03debadf36c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.content.Context;
import android.content.pm.UserInfo;
@@ -348,7 +347,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver,
- @NonNull String opPackageName) {
+ @NonNull String opPackageName, boolean shouldLogMetrics) {
mHandler.post(() -> {
final IFingerprint daemon = getHalInstance();
if (daemon == null) {
@@ -370,7 +369,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
- mUdfpsOverlayController, maxTemplatesPerUser);
+ mUdfpsOverlayController, maxTemplatesPerUser, shouldLogMetrics);
scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
index 1f1d19d07121..093c9449c498 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintResetLockoutClient.java
@@ -50,7 +50,8 @@ class FingerprintResetLockoutClient extends ClientMonitor<ISession> {
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 74549b917e82..95c4cee7e59e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -122,7 +122,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), true/* shouldLogMetrics */);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index b8d27aa61806..f5ce8943c188 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
import android.app.SynchronousUserSwitchObserver;
import android.app.TaskStackListener;
import android.app.UserSwitchObserver;
@@ -548,14 +547,16 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@Override
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
- @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName) {
+ @NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
+ boolean shouldLogMetrics) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
- ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController);
+ ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController,
+ shouldLogMetrics);
mScheduler.scheduleClientMonitor(client, new ClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull ClientMonitor<?> clientMonitor,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 4747488e5a70..c00dd048eeda 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -56,7 +56,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
- statsClient);
+ statsClient, true /* shouldLogMetrics */);
mUdfpsOverlayController = udfpsOverlayController;
mIsStrongBiometric = isStrongBiometric;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index af61a8be3052..a261b0b8fcdf 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -52,10 +52,11 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int timeoutSec, int sensorId,
- @Nullable IUdfpsOverlayController udfpsOverlayController) {
+ @Nullable IUdfpsOverlayController udfpsOverlayController,
+ boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
- true /* shouldVibrate */);
+ true /* shouldVibrate */, shouldLogMetrics);
mUdfpsOverlayController = udfpsOverlayController;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
index 00e2413c2f38..c785eeff6d9c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java
@@ -50,7 +50,8 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
- BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+ BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
+ true /* shouldLogMetrics */);
mCurrentUserId = currentUserId;
mHasEnrolledBiometrics = hasEnrolledBiometrics;
mAuthenticatorIds = authenticatorIds;
diff --git a/services/core/java/com/android/server/content/OWNERS b/services/core/java/com/android/server/content/OWNERS
new file mode 100644
index 000000000000..b6a9fe869ffa
--- /dev/null
+++ b/services/core/java/com/android/server/content/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/am/OWNERS \ No newline at end of file
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index eb61a1c2ad40..fa063b223250 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -46,6 +46,7 @@ import com.android.internal.BrightnessSynchronizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
+import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
import java.io.PrintWriter;
@@ -195,6 +196,9 @@ class AutomaticBrightnessController {
private boolean mShortTermModelValid;
private float mShortTermModelAnchor;
+ // Controls High Brightness Mode.
+ private HighBrightnessModeController mHbmController;
+
// Context-sensitive brightness configurations require keeping track of the foreground app's
// package name and category, which is done by registering a TaskStackListener to call back to
// us onTaskStackChanged, and then using the ActivityTaskManager to get the foreground app's
@@ -216,12 +220,12 @@ class AutomaticBrightnessController {
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context) {
+ HysteresisLevels screenBrightnessThresholds, LogicalDisplay display, Context context) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
- ambientBrightnessThresholds, screenBrightnessThresholds, context
+ ambientBrightnessThresholds, screenBrightnessThresholds, display, context
);
}
@@ -232,7 +236,7 @@ class AutomaticBrightnessController {
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
- HysteresisLevels screenBrightnessThresholds, Context context) {
+ HysteresisLevels screenBrightnessThresholds, LogicalDisplay display, Context context) {
mInjector = injector;
mContext = context;
mCallbacks = callbacks;
@@ -269,6 +273,20 @@ class AutomaticBrightnessController {
mPendingForegroundAppPackageName = null;
mForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
+
+ final DisplayDeviceConfig ddConfig =
+ display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig();
+ HighBrightnessModeData hbmData =
+ ddConfig != null ? ddConfig.getHighBrightnessModeData() : null;
+
+ final Runnable hbmChangeCallback = () -> {
+ updateAutoBrightness(true /*sendUpdate*/, false /*userInitiatedChange*/);
+ // TODO: b/175937645 - Callback to DisplayManagerService to indicate a change to the HBM
+ // allowance has been made so that the brightness limits can be calculated
+ // appropriately.
+ };
+ mHbmController = new HighBrightnessModeController(mHandler, brightnessMin, brightnessMax,
+ hbmData, hbmChangeCallback);
}
/**
@@ -538,6 +556,7 @@ class AutomaticBrightnessController {
mAmbientLux = lux;
mAmbientBrighteningThreshold = mAmbientBrightnessThresholds.getBrighteningThreshold(lux);
mAmbientDarkeningThreshold = mAmbientBrightnessThresholds.getDarkeningThreshold(lux);
+ mHbmController.onAmbientLuxChange(mAmbientLux);
// If the short term model was invalidated and the change is drastic enough, reset it.
if (!mShortTermModelValid && mShortTermModelAnchor != -1) {
@@ -751,6 +770,7 @@ class AutomaticBrightnessController {
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
mScreenDarkeningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
+ mHbmController.onAutoBrightnessChanged(mScreenAutoBrightness);
if (sendUpdate) {
mCallbacks.updateBrightness();
@@ -761,7 +781,7 @@ class AutomaticBrightnessController {
// Clamps values with float range [0.0-1.0]
private float clampScreenBrightness(float value) {
return MathUtils.constrain(value,
- mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+ mHbmController.getCurrentBrightnessMin(), mHbmController.getCurrentBrightnessMax());
}
private void prepareBrightnessAdjustmentSample() {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 3516981c92a6..cd17cfef2726 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -37,7 +37,6 @@ abstract class DisplayDevice {
private final DisplayAdapter mDisplayAdapter;
private final IBinder mDisplayToken;
private final String mUniqueId;
- private DisplayDeviceConfig mDisplayDeviceConfig;
// The display device does not manage these properties itself, they are set by
// the display manager service. The display device shouldn't really be looking at these.
@@ -71,12 +70,11 @@ abstract class DisplayDevice {
/*
* Gets the DisplayDeviceConfig for this DisplayDevice.
- * Returns null for this device but is overridden in LocalDisplayDevice.
*
- * @return The DisplayDeviceConfig.
+ * @return The DisplayDeviceConfig; {@code null} if not overridden.
*/
public DisplayDeviceConfig getDisplayDeviceConfig() {
- return mDisplayDeviceConfig;
+ return null;
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 0a30e07165f9..68708d36f259 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -16,6 +16,7 @@
package com.android.server.display;
+import android.annotation.NonNull;
import android.content.Context;
import android.os.Environment;
import android.os.PowerManager;
@@ -25,6 +26,8 @@ import android.view.DisplayAddress;
import com.android.internal.BrightnessSynchronizer;
import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
+import com.android.server.display.config.HbmTiming;
+import com.android.server.display.config.HighBrightnessMode;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.XmlParser;
@@ -61,19 +64,20 @@ public class DisplayDeviceConfig {
private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d";
private static final String NO_SUFFIX_FORMAT = "%d";
private static final long STABLE_FLAG = 1L << 62;
-
// Float.NaN (used as invalid for brightness) cannot be stored in config.xml
// so -2 is used instead
private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
+ private final Context mContext;
+
private float[] mNits;
private float[] mBrightness;
private float mBrightnessMinimum = Float.NaN;
private float mBrightnessMaximum = Float.NaN;
private float mBrightnessDefault = Float.NaN;
private List<String> mQuirks;
-
- private final Context mContext;
+ private boolean mIsHighBrightnessModeEnabled = false;
+ private HighBrightnessModeData mHbmData;
private DisplayDeviceConfig(Context context) {
mContext = context;
@@ -182,6 +186,19 @@ public class DisplayDeviceConfig {
return mQuirks != null && mQuirks.contains(quirkValue);
}
+ /**
+ * @return high brightness mode configuration data for the display.
+ */
+ public HighBrightnessModeData getHighBrightnessModeData() {
+ if (!mIsHighBrightnessModeEnabled || mHbmData == null) {
+ return null;
+ }
+
+ HighBrightnessModeData hbmData = new HighBrightnessModeData();
+ mHbmData.copyTo(hbmData);
+ return hbmData;
+ }
+
@Override
public String toString() {
String str = "DisplayDeviceConfig{"
@@ -191,10 +208,16 @@ public class DisplayDeviceConfig {
+ ", mBrightnessMaximum=" + mBrightnessMaximum
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
+ + ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ + ", mHbmData=" + mHbmData
+ "}";
return str;
}
+ private float getMaxBrightness() {
+ return mBrightness[mBrightness.length - 1];
+ }
+
private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory,
String suffixFormat, long idNumber) {
@@ -240,6 +263,7 @@ public class DisplayDeviceConfig {
loadBrightnessMap(config);
loadBrightnessDefaultFromDdcXml(config);
loadBrightnessConstraintsFromConfigXml();
+ loadHighBrightnessModeData(config);
loadQuirks(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
@@ -353,4 +377,66 @@ public class DisplayDeviceConfig {
mQuirks = new ArrayList<>(quirks.getQuirk());
}
}
+
+ private void loadHighBrightnessModeData(DisplayConfiguration config) {
+ final HighBrightnessMode hbm = config.getHighBrightnessMode();
+ if (hbm != null) {
+ mIsHighBrightnessModeEnabled = hbm.getEnabled();
+ mHbmData = new HighBrightnessModeData();
+ mHbmData.minimumLux = hbm.getMinimumLux_all().floatValue();
+ mHbmData.transitionPoint = hbm.getTransitionPoint_all().floatValue();
+ if (mHbmData.transitionPoint >= getMaxBrightness()) {
+ throw new IllegalArgumentException("HBM transition point invalid. "
+ + mHbmData.transitionPoint + " is not less than "
+ + getMaxBrightness());
+ }
+ final HbmTiming hbmTiming = hbm.getTiming_all();
+ mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
+ mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
+ mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
+ }
+ }
+
+ /**
+ * Container for high brightness mode configuration data.
+ */
+ static class HighBrightnessModeData {
+ /** Minimum lux needed to enter high brightness mode */
+ public float minimumLux;
+
+ /** Brightness level at which we transition from normal to high-brightness. */
+ public float transitionPoint;
+
+ /** Time window for HBM. */
+ public long timeWindowMillis;
+
+ /** Maximum time HBM is allowed to be during in a {@code timeWindowMillis}. */
+ public long timeMaxMillis;
+
+ /** Minimum time that HBM can be on before being enabled. */
+ public long timeMinMillis;
+
+ /**
+ * Copies the HBM data to the specified parameter instance.
+ * @param other the instance to copy data to.
+ */
+ public void copyTo(@NonNull HighBrightnessModeData other) {
+ other.minimumLux = minimumLux;
+ other.transitionPoint = transitionPoint;
+ other.timeWindowMillis = timeWindowMillis;
+ other.timeMaxMillis = timeMaxMillis;
+ other.timeMinMillis = timeMinMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "HBM{"
+ + "minLux: " + minimumLux
+ + ", transition: " + transitionPoint
+ + ", timeWindow: " + timeWindowMillis + "ms"
+ + ", timeMax: " + timeMaxMillis + "ms"
+ + ", timeMin: " + timeMinMillis
+ + "} ";
+ }
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 6fa244e2d9ee..60e4595a7679 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1100,7 +1100,7 @@ public final class DisplayManagerService extends SystemService {
recordStableDisplayStatsIfNeededLocked(display);
recordTopInsetLocked(display);
}
- addDisplayPowerControllerLocked(displayId);
+ addDisplayPowerControllerLocked(display);
mDisplayStates.append(displayId, Display.STATE_OFF);
mDisplayBrightnesses.append(displayId, display.getDisplayInfoLocked().brightnessDefault);
@@ -1132,6 +1132,11 @@ public final class DisplayManagerService extends SystemService {
// this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
scheduleTraversalLocked(false);
+
+ DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
+ if (dpc != null) {
+ dpc.onDisplayChanged();
+ }
}
private void handleLogicalDisplayFrameRateOverridesChangedLocked(
@@ -1860,18 +1865,18 @@ public final class DisplayManagerService extends SystemService {
private void initializeDisplayPowerControllersLocked() {
mLogicalDisplayMapper.forEachLocked((logicalDisplay) -> addDisplayPowerControllerLocked(
- logicalDisplay.getDisplayIdLocked()));
+ logicalDisplay));
}
- private void addDisplayPowerControllerLocked(int displayId) {
+ private void addDisplayPowerControllerLocked(LogicalDisplay display) {
if (mPowerHandler == null) {
// initPowerManagement has not yet been called.
return;
}
final DisplayPowerController displayPowerController = new DisplayPowerController(
mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager,
- mDisplayBlanker, mLogicalDisplayMapper.getLocked(displayId));
- mDisplayPowerControllers.append(displayId, displayPowerController);
+ mDisplayBlanker, display);
+ mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
}
private final class DisplayManagerHandler extends Handler {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index e31704f03cd9..811625b06cf0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -523,7 +523,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
- screenBrightnessThresholds, context);
+ screenBrightnessThresholds, logicalDisplay, context);
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
@@ -674,6 +674,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return mAutomaticBrightnessController.getDefaultConfig();
}
+ /**
+ * Notified when the display is changed. We use this to apply any changes that might be needed
+ * when displays get swapped on foldable devices. For example, different brightness properties
+ * of each display need to be properly reflected in AutomaticBrightnessController.
+ */
+ public void onDisplayChanged() {
+ // TODO: b/175821789 - Support high brightness on multiple (folding) displays
+ }
+
private void sendUpdatePowerState() {
synchronized (mLock) {
sendUpdatePowerStateLocked();
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
new file mode 100644
index 000000000000..12b810f906f2
--- /dev/null
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -0,0 +1,260 @@
+/*
+ * 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.display;
+
+import android.os.Handler;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.server.display.DisplayDeviceConfig.HighBrightnessModeData;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Controls the status of high-brightness mode for devices that support it. This class assumes that
+ * an instance is always created even if a device does not support high-brightness mode (HBM); in
+ * the case where it is not supported, the majority of the logic is skipped. On devices that support
+ * HBM, we keep track of the ambient lux as well as historical usage of HBM to determine when HBM is
+ * allowed and not. This class's output is simply a brightness-range maximum value (queried via
+ * {@link #getCurrentBrightnessMax}) that changes depending on whether HBM is enabled or not.
+ */
+class HighBrightnessModeController {
+ private static final String TAG = "HighBrightnessModeController";
+
+ private static final boolean DEBUG_HBM = false;
+
+ private final float mBrightnessMin;
+ private final float mBrightnessMax;
+ private final HighBrightnessModeData mHbmData;
+ private final Handler mHandler;
+ private final Runnable mHbmChangeCallback;
+ private final Runnable mRecalcRunnable;
+
+ private boolean mIsInAllowedAmbientRange = false;
+ private boolean mIsTimeAvailable = false;
+ private float mAutoBrightness;
+
+ /**
+ * If HBM is currently running, this is the start time for the current HBM session.
+ */
+ private long mRunningStartTimeMillis = -1;
+
+ /**
+ * List of previous HBM-events ordered from most recent to least recent.
+ * Meant to store only the events that fall into the most recent
+ * {@link mHbmData.timeWindowSecs}.
+ */
+ private LinkedList<HbmEvent> mEvents = new LinkedList<>();
+
+ HighBrightnessModeController(Handler handler, float brightnessMin, float brightnessMax,
+ HighBrightnessModeData hbmData, Runnable hbmChangeCallback) {
+ mHandler = handler;
+ mBrightnessMin = brightnessMin;
+ mBrightnessMax = brightnessMax;
+ mHbmData = hbmData;
+ mHbmChangeCallback = hbmChangeCallback;
+ mAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
+ mRecalcRunnable = () -> {
+ boolean oldIsAllowed = isCurrentlyAllowed();
+ recalculateTimeAllowance();
+ if (oldIsAllowed != isCurrentlyAllowed()) {
+ // Our allowed state has changed; tell AutomaticBrightnessController
+ // to update the brightness.
+ if (mHbmChangeCallback != null) {
+ mHbmChangeCallback.run();
+ }
+ }
+ };
+ }
+
+ float getCurrentBrightnessMin() {
+ return mBrightnessMin;
+ }
+
+ float getCurrentBrightnessMax() {
+ if (!deviceSupportsHbm() || isCurrentlyAllowed()) {
+ // Either the device doesn't support HBM, or HBM range is currently allowed (device
+ // it in a high-lux environment). In either case, return the highest brightness
+ // level supported by the device.
+ return mBrightnessMax;
+ } else {
+ // Hbm is not allowed, only allow up to the brightness where we
+ // transition to high brightness mode.
+ return mHbmData.transitionPoint;
+ }
+ }
+
+ void onAmbientLuxChange(float ambientLux) {
+ if (!deviceSupportsHbm()) {
+ return;
+ }
+
+ final boolean isHighLux = (ambientLux >= mHbmData.minimumLux);
+ if (isHighLux != mIsInAllowedAmbientRange) {
+ mIsInAllowedAmbientRange = isHighLux;
+ recalculateTimeAllowance();
+ }
+ }
+
+ void onAutoBrightnessChanged(float autoBrightness) {
+ if (!deviceSupportsHbm()) {
+ return;
+ }
+ final float oldAutoBrightness = mAutoBrightness;
+ mAutoBrightness = autoBrightness;
+
+ // If we are starting or ending a high brightness mode session, store the current
+ // session in mRunningStartTimeMillis, or the old one in mEvents.
+ final boolean wasOldBrightnessHigh = oldAutoBrightness > mHbmData.transitionPoint;
+ final boolean isNewBrightnessHigh = mAutoBrightness > mHbmData.transitionPoint;
+ if (wasOldBrightnessHigh != isNewBrightnessHigh) {
+ final long currentTime = SystemClock.uptimeMillis();
+ if (isNewBrightnessHigh) {
+ mRunningStartTimeMillis = currentTime;
+ } else {
+ mEvents.addFirst(new HbmEvent(mRunningStartTimeMillis, currentTime));
+ mRunningStartTimeMillis = -1;
+
+ if (DEBUG_HBM) {
+ Slog.d(TAG, "New HBM event: " + mEvents.getFirst());
+ }
+ }
+ }
+
+ recalculateTimeAllowance();
+ }
+
+ private boolean isCurrentlyAllowed() {
+ return mIsTimeAvailable && mIsInAllowedAmbientRange;
+ }
+
+ private boolean deviceSupportsHbm() {
+ return mHbmData != null;
+ }
+
+ /**
+ * Recalculates the allowable HBM time.
+ */
+ private void recalculateTimeAllowance() {
+ final long currentTime = SystemClock.uptimeMillis();
+ long timeAlreadyUsed = 0;
+
+ // First, lets see how much time we've taken for any currently running
+ // session of HBM.
+ if (mRunningStartTimeMillis > 0) {
+ if (mRunningStartTimeMillis > currentTime) {
+ Slog.e(TAG, "Start time set to the future. curr: " + currentTime
+ + ", start: " + mRunningStartTimeMillis);
+ mRunningStartTimeMillis = currentTime;
+ }
+ timeAlreadyUsed = currentTime - mRunningStartTimeMillis;
+ }
+
+ if (DEBUG_HBM) {
+ Slog.d(TAG, "Time already used after current session: " + timeAlreadyUsed);
+ }
+
+ // Next, lets iterate through the history of previous sessions and add those times.
+ final long windowstartTimeMillis = currentTime - mHbmData.timeWindowMillis;
+ Iterator<HbmEvent> it = mEvents.iterator();
+ while (it.hasNext()) {
+ final HbmEvent event = it.next();
+
+ // If this event ended before the current Timing window, discard forever and ever.
+ if (event.endTimeMillis < windowstartTimeMillis) {
+ it.remove();
+ continue;
+ }
+
+ final long startTimeMillis = Math.max(event.startTimeMillis, windowstartTimeMillis);
+ timeAlreadyUsed += event.endTimeMillis - startTimeMillis;
+ }
+
+ if (DEBUG_HBM) {
+ Slog.d(TAG, "Time already used after all sessions: " + timeAlreadyUsed);
+ }
+
+ // See how much allowable time we have left.
+ final long remainingTime = Math.max(0, mHbmData.timeMaxMillis - timeAlreadyUsed);
+
+ // We allow HBM if there is more than the minimum required time available
+ // or if brightness is already in the high range, if there is any time left at all.
+ final boolean isAllowedWithoutRestrictions = remainingTime >= mHbmData.timeMinMillis;
+ final boolean isOnlyAllowedToStayOn = !isAllowedWithoutRestrictions
+ && remainingTime > 0 && mAutoBrightness > mHbmData.transitionPoint;
+ mIsTimeAvailable = isAllowedWithoutRestrictions || isOnlyAllowedToStayOn;
+
+ // Calculate the time at which we want to recalculate mIsTimeAvailable in case a lux or
+ // brightness change doesn't happen before then.
+ long nextTimeout = -1;
+ if (mAutoBrightness > mHbmData.transitionPoint) {
+ // if we're in high-lux now, timeout when we run out of allowed time.
+ nextTimeout = currentTime + remainingTime;
+ } else if (!mIsTimeAvailable && mEvents.size() > 0) {
+ // If we are not allowed...timeout when the oldest event moved outside of the timing
+ // window by at least minTime. Basically, we're calculating the soonest time we can
+ // get {@code timeMinMillis} back to us.
+ final HbmEvent lastEvent = mEvents.getLast();
+ final long startTimePlusMinMillis =
+ Math.max(windowstartTimeMillis, lastEvent.startTimeMillis)
+ + mHbmData.timeMinMillis;
+ final long timeWhenMinIsGainedBack =
+ currentTime + (startTimePlusMinMillis - windowstartTimeMillis) - remainingTime;
+ nextTimeout = timeWhenMinIsGainedBack;
+ }
+
+ if (DEBUG_HBM) {
+ Slog.d(TAG, "HBM recalculated. IsAllowedWithoutRestrictions: "
+ + isAllowedWithoutRestrictions
+ + ", isOnlyAllowedToStayOn: " + isOnlyAllowedToStayOn
+ + ", remainingAllowedTime: " + remainingTime
+ + ", isLuxHigh: " + mIsInAllowedAmbientRange
+ + ", isHBMCurrentlyAllowed: " + isCurrentlyAllowed()
+ + ", brightness: " + mAutoBrightness
+ + ", RunningStartTimeMillis: " + mRunningStartTimeMillis
+ + ", nextTimeout: " + (nextTimeout != -1 ? (nextTimeout - currentTime) : -1)
+ + ", events: " + mEvents);
+ }
+
+ if (nextTimeout != -1) {
+ mHandler.removeCallbacks(mRecalcRunnable);
+ mHandler.postAtTime(mRecalcRunnable, nextTimeout);
+ }
+ }
+
+ /**
+ * Represents an event in which High Brightness Mode was enabled.
+ */
+ private static class HbmEvent {
+ public long startTimeMillis;
+ public long endTimeMillis;
+
+ HbmEvent(long startTimeMillis, long endTimeMillis) {
+ this.startTimeMillis = startTimeMillis;
+ this.endTimeMillis = endTimeMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "[Event: {" + startTimeMillis + ", " + endTimeMillis + "}, total: "
+ + ((endTimeMillis - startTimeMillis) / 1000) + "]";
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/timezone/ControllerImpl.java b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
index 03ce8ecd1cc0..2b3c0bff8548 100644
--- a/services/core/java/com/android/server/location/timezone/ControllerImpl.java
+++ b/services/core/java/com/android/server/location/timezone/ControllerImpl.java
@@ -610,6 +610,38 @@ class ControllerImpl extends LocationTimeZoneProviderController {
}
}
+ /**
+ * Sets whether the controller should record provider state changes for later dumping via
+ * {@link #getStateForTests()}.
+ */
+ void setProviderStateRecordingEnabled(boolean enabled) {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ mPrimaryProvider.setStateChangeRecordingEnabled(enabled);
+ mSecondaryProvider.setStateChangeRecordingEnabled(enabled);
+ }
+ }
+
+ /**
+ * Returns a snapshot of the current controller state for tests.
+ */
+ @NonNull
+ LocationTimeZoneManagerServiceState getStateForTests() {
+ mThreadingDomain.assertCurrentThread();
+
+ synchronized (mSharedLock) {
+ LocationTimeZoneManagerServiceState.Builder builder =
+ new LocationTimeZoneManagerServiceState.Builder();
+ if (mLastSuggestion != null) {
+ builder.setLastSuggestion(mLastSuggestion);
+ }
+ builder.setPrimaryProviderStateChanges(mPrimaryProvider.getRecordedStates())
+ .setSecondaryProviderStateChanges(mSecondaryProvider.getRecordedStates());
+ return builder.build();
+ }
+ }
+
@Nullable
private LocationTimeZoneProvider getLocationTimeZoneProvider(@NonNull String providerName) {
LocationTimeZoneProvider targetProvider;
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
index 9f159fbe7b65..54535eb50130 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerService.java
@@ -17,11 +17,10 @@
package com.android.server.location.timezone;
import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PRIMARY;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_SECONDARY;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,7 +32,6 @@ import android.os.Handler;
import android.os.RemoteCallback;
import android.os.ResultReceiver;
import android.os.ShellCallback;
-import android.os.SystemProperties;
import android.service.timezone.TimeZoneProviderService;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -42,6 +40,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
import com.android.server.SystemService;
import com.android.server.timezonedetector.TimeZoneDetectorInternal;
@@ -161,6 +160,14 @@ public class LocationTimeZoneManagerService extends Binder {
@GuardedBy("mSharedLock")
private ControllerEnvironmentImpl mEnvironment;
+ @GuardedBy("mSharedLock")
+ @NonNull
+ private String mPrimaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
+
+ @GuardedBy("mSharedLock")
+ @NonNull
+ private String mSecondaryProviderModeOverride = PROVIDER_MODE_OVERRIDE_NONE;
+
LocationTimeZoneManagerService(Context context) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
@@ -231,9 +238,9 @@ public class LocationTimeZoneManagerService extends Binder {
private LocationTimeZoneProvider createPrimaryProvider() {
LocationTimeZoneProviderProxy proxy;
- if (isInSimulationMode(PRIMARY_PROVIDER_NAME)) {
+ if (isProviderInSimulationMode(PRIMARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (isDisabled(PRIMARY_PROVIDER_NAME)) {
+ } else if (isProviderDisabled(PRIMARY_PROVIDER_NAME)) {
proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
proxy = new RealLocationTimeZoneProviderProxy(
@@ -250,9 +257,9 @@ public class LocationTimeZoneManagerService extends Binder {
private LocationTimeZoneProvider createSecondaryProvider() {
LocationTimeZoneProviderProxy proxy;
- if (isInSimulationMode(SECONDARY_PROVIDER_NAME)) {
+ if (isProviderInSimulationMode(SECONDARY_PROVIDER_NAME)) {
proxy = new SimulatedLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
- } else if (isDisabled(SECONDARY_PROVIDER_NAME)) {
+ } else if (isProviderDisabled(SECONDARY_PROVIDER_NAME)) {
proxy = new NullLocationTimeZoneProviderProxy(mContext, mThreadingDomain);
} else {
proxy = new RealLocationTimeZoneProviderProxy(
@@ -268,16 +275,14 @@ public class LocationTimeZoneManagerService extends Binder {
}
/** Used for bug triage and in tests to simulate provider events. */
- private static boolean isInSimulationMode(String providerName) {
- return isProviderModeSetInSystemProperties(providerName,
- SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED);
+ private boolean isProviderInSimulationMode(String providerName) {
+ return isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_SIMULATED);
}
/** Used for bug triage, tests and experiments to remove a provider. */
- private boolean isDisabled(String providerName) {
+ private boolean isProviderDisabled(String providerName) {
return !isProviderEnabledInConfig(providerName)
- || isProviderModeSetInSystemProperties(
- providerName, SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED);
+ || isProviderModeOverrideSet(providerName, PROVIDER_MODE_OVERRIDE_DISABLED);
}
private boolean isProviderEnabledInConfig(String providerName) {
@@ -299,25 +304,18 @@ public class LocationTimeZoneManagerService extends Binder {
return resources.getBoolean(providerEnabledConfigId);
}
- private static boolean isProviderModeSetInSystemProperties(
- @NonNull String providerName, @NonNull String mode) {
- String systemPropertyKey;
+ private boolean isProviderModeOverrideSet(@NonNull String providerName, @NonNull String mode) {
switch (providerName) {
case PRIMARY_PROVIDER_NAME: {
- systemPropertyKey = SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PRIMARY;
- break;
+ return Objects.equals(mPrimaryProviderModeOverride, mode);
}
case SECONDARY_PROVIDER_NAME: {
- systemPropertyKey = SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_SECONDARY;
- break;
+ return Objects.equals(mSecondaryProviderModeOverride, mode);
}
default: {
throw new IllegalArgumentException(providerName);
}
}
-
- String systemPropertyProviderMode = SystemProperties.get(systemPropertyKey, null);
- return Objects.equals(systemPropertyProviderMode, mode);
}
/**
@@ -347,6 +345,67 @@ public class LocationTimeZoneManagerService extends Binder {
this, in, out, err, args, callback, resultReceiver);
}
+ /** Sets this service into provider state recording mode for tests. */
+ void setProviderModeOverride(@NonNull String providerName, @NonNull String mode) {
+ enforceManageTimeZoneDetectorPermission();
+
+ Preconditions.checkArgument(
+ PRIMARY_PROVIDER_NAME.equals(providerName)
+ || SECONDARY_PROVIDER_NAME.equals(providerName));
+ Preconditions.checkArgument(PROVIDER_MODE_OVERRIDE_DISABLED.equals(mode)
+ || PROVIDER_MODE_OVERRIDE_SIMULATED.equals(mode)
+ || PROVIDER_MODE_OVERRIDE_NONE.equals(mode));
+
+ mThreadingDomain.postAndWait(() -> {
+ synchronized (mSharedLock) {
+ switch (providerName) {
+ case PRIMARY_PROVIDER_NAME: {
+ mPrimaryProviderModeOverride = mode;
+ break;
+ }
+ case SECONDARY_PROVIDER_NAME: {
+ mSecondaryProviderModeOverride = mode;
+ break;
+ }
+ }
+ }
+ }, BLOCKING_OP_WAIT_DURATION_MILLIS);
+ }
+
+ /** Sets this service into provider state recording mode for tests. */
+ void setProviderStateRecordingEnabled(boolean enabled) {
+ enforceManageTimeZoneDetectorPermission();
+
+ mThreadingDomain.postAndWait(() -> {
+ synchronized (mSharedLock) {
+ if (mLocationTimeZoneDetectorController != null) {
+ mLocationTimeZoneDetectorController.setProviderStateRecordingEnabled(enabled);
+ }
+ }
+ }, BLOCKING_OP_WAIT_DURATION_MILLIS);
+ }
+
+ /** Returns a snapshot of the current controller state for tests. */
+ @NonNull
+ LocationTimeZoneManagerServiceState getStateForTests() {
+ enforceManageTimeZoneDetectorPermission();
+
+ try {
+ return mThreadingDomain.postAndWait(
+ () -> {
+ synchronized (mSharedLock) {
+ if (mLocationTimeZoneDetectorController == null) {
+ return null;
+ }
+ return mLocationTimeZoneDetectorController.getStateForTests();
+ }
+ },
+ BLOCKING_OP_WAIT_DURATION_MILLIS);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
/**
* Passes a {@link TestCommand} to the specified provider and waits for the response.
*/
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerServiceState.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerServiceState.java
new file mode 100644
index 000000000000..b1dd55f3d4fd
--- /dev/null
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerServiceState.java
@@ -0,0 +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 com.android.server.location.timezone;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState;
+import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/** A snapshot of the location time zone manager service's state for tests. */
+final class LocationTimeZoneManagerServiceState {
+
+ @Nullable private final GeolocationTimeZoneSuggestion mLastSuggestion;
+ @NonNull private final List<ProviderState> mPrimaryProviderStates;
+ @NonNull private final List<ProviderState> mSecondaryProviderStates;
+
+ LocationTimeZoneManagerServiceState(@NonNull Builder builder) {
+ mLastSuggestion = builder.mLastSuggestion;
+ mPrimaryProviderStates = Objects.requireNonNull(builder.mPrimaryProviderStates);
+ mSecondaryProviderStates = Objects.requireNonNull(builder.mSecondaryProviderStates);
+ }
+
+ @Nullable
+ public GeolocationTimeZoneSuggestion getLastSuggestion() {
+ return mLastSuggestion;
+ }
+
+ @NonNull
+ public List<ProviderState> getPrimaryProviderStates() {
+ return Collections.unmodifiableList(mPrimaryProviderStates);
+ }
+
+ @NonNull
+ public List<ProviderState> getSecondaryProviderStates() {
+ return Collections.unmodifiableList(mSecondaryProviderStates);
+ }
+
+ @Override
+ public String toString() {
+ return "LocationTimeZoneManagerServiceState{"
+ + "mLastSuggestion=" + mLastSuggestion
+ + ", mPrimaryProviderStates=" + mPrimaryProviderStates
+ + ", mSecondaryProviderStates=" + mSecondaryProviderStates
+ + '}';
+ }
+
+ static final class Builder {
+
+ private GeolocationTimeZoneSuggestion mLastSuggestion;
+ private List<ProviderState> mPrimaryProviderStates;
+ private List<ProviderState> mSecondaryProviderStates;
+
+ @NonNull
+ Builder setLastSuggestion(@NonNull GeolocationTimeZoneSuggestion lastSuggestion) {
+ mLastSuggestion = Objects.requireNonNull(lastSuggestion);
+ return this;
+ }
+
+ @NonNull
+ Builder setPrimaryProviderStateChanges(@NonNull List<ProviderState> primaryProviderStates) {
+ mPrimaryProviderStates = new ArrayList<>(primaryProviderStates);
+ return this;
+ }
+
+ @NonNull
+ Builder setSecondaryProviderStateChanges(
+ @NonNull List<ProviderState> secondaryProviderStates) {
+ mSecondaryProviderStates = new ArrayList<>(secondaryProviderStates);
+ return this;
+ }
+
+ @NonNull
+ LocationTimeZoneManagerServiceState build() {
+ return new LocationTimeZoneManagerServiceState(this);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerShellCommand.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerShellCommand.java
index 554df07aa485..6f9863c9bd09 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerShellCommand.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneManagerShellCommand.java
@@ -15,23 +15,46 @@
*/
package com.android.server.location.timezone;
+import static android.app.time.LocationTimeZoneManager.DUMP_STATE_OPTION_PROTO;
import static android.app.time.LocationTimeZoneManager.PRIMARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_DISABLED;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_NONE;
+import static android.app.time.LocationTimeZoneManager.PROVIDER_MODE_OVERRIDE_SIMULATED;
import static android.app.time.LocationTimeZoneManager.SECONDARY_PROVIDER_NAME;
+import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_DUMP_STATE;
+import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_RECORD_PROVIDER_STATES;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND;
+import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_START;
import static android.app.time.LocationTimeZoneManager.SHELL_COMMAND_STOP;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PRIMARY;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_SECONDARY;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED;
-import static android.app.time.LocationTimeZoneManager.SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED;
+
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_PERM_FAILED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STOPPED;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_UNKNOWN;
import android.annotation.NonNull;
+import android.app.time.GeolocationTimeZoneSuggestionProto;
+import android.app.time.LocationTimeZoneManagerProto;
+import android.app.time.LocationTimeZoneManagerServiceStateProto;
+import android.app.time.TimeZoneProviderStateProto;
import android.os.Bundle;
import android.os.ShellCommand;
+import android.util.IndentingPrintWriter;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.dump.DualDumpOutputStream;
+import com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.ProviderStateEnum;
+import com.android.server.timezonedetector.GeolocationTimeZoneSuggestion;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/** Implements the shell command interface for {@link LocationTimeZoneManagerService}. */
class LocationTimeZoneManagerShellCommand extends ShellCommand {
@@ -58,9 +81,18 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand {
case SHELL_COMMAND_STOP: {
return runStop();
}
+ case SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE: {
+ return runSetProviderModeOverride();
+ }
case SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND: {
return runSendProviderTestCommand();
}
+ case SHELL_COMMAND_RECORD_PROVIDER_STATES: {
+ return runRecordProviderStates();
+ }
+ case SHELL_COMMAND_DUMP_STATE: {
+ return runDumpControllerState();
+ }
default: {
return handleDefaultCommands(cmd);
}
@@ -70,35 +102,42 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand {
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
- pw.println("Location Time Zone Manager (location_time_zone_manager) commands:");
+ pw.println("Location Time Zone Manager (location_time_zone_manager) commands for tests:");
pw.println(" help");
pw.println(" Print this help text.");
pw.printf(" %s\n", SHELL_COMMAND_START);
pw.println(" Starts the location_time_zone_manager, creating time zone providers.");
pw.printf(" %s\n", SHELL_COMMAND_STOP);
pw.println(" Stops the location_time_zone_manager, destroying time zone providers.");
+ pw.printf(" %s <provider name> <mode>\n", SHELL_COMMAND_SET_PROVIDER_MODE_OVERRIDE);
+ pw.println(" Sets a provider into a test mode next time the service started.");
+ pw.printf(" Values: %s|%s|%s\n", PROVIDER_MODE_OVERRIDE_NONE,
+ PROVIDER_MODE_OVERRIDE_DISABLED, PROVIDER_MODE_OVERRIDE_SIMULATED);
+ pw.printf(" %s (true|false)\n", SHELL_COMMAND_RECORD_PROVIDER_STATES);
+ pw.printf(" Enables / disables provider state recording mode. See also %s. The default"
+ + " state is always \"false\".\n", SHELL_COMMAND_DUMP_STATE);
+ pw.println(" Note: When enabled, this mode consumes memory and it is only intended for"
+ + " testing.");
+ pw.println(" It should be disabled after use, or the device can be rebooted to"
+ + " reset the mode to disabled.");
+ pw.println(" Disabling (or enabling repeatedly) clears any existing stored states.");
+ pw.printf(" %s [%s]\n", SHELL_COMMAND_DUMP_STATE, DUMP_STATE_OPTION_PROTO);
+ pw.println(" Dumps Location Time Zone Manager state for tests as text or binary proto"
+ + " form.");
+ pw.println(" See the LocationTimeZoneManagerServiceStateProto definition for details.");
pw.printf(" %s <provider name> <test command>\n",
SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println(" Passes a test command to the named provider.");
pw.println();
- pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
- pw.println();
pw.printf("<provider name> = One of %s\n", VALID_PROVIDER_NAMES);
pw.println();
- pw.println("<test command> encoding:");
+ pw.printf("%s details:\n", SHELL_COMMAND_SEND_PROVIDER_TEST_COMMAND);
pw.println();
- TestCommand.printShellCommandEncodingHelp(pw);
+ pw.println("Provider <test command> encoding:");
pw.println();
- pw.printf("Provider modes can be modified by setting the \"%s\" or \"%s\"\n system"
- + " property and restarting the service or rebooting the device.\n",
- SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_PRIMARY,
- SYSTEM_PROPERTY_KEY_PROVIDER_MODE_OVERRIDE_SECONDARY);
- pw.println("Values are:");
- pw.printf(" %s - simulation mode (see below for commands)\n",
- SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_SIMULATED);
- pw.printf(" %s - disabled mode\n", SYSTEM_PROPERTY_VALUE_PROVIDER_MODE_DISABLED);
+ TestCommand.printShellCommandEncodingHelp(pw);
pw.println();
- pw.println("Simulated providers can be used to test the system server behavior or to"
+ pw.println("Simulated provider mode can be used to test the system server behavior or to"
+ " reproduce bugs without the complexity of using real providers.");
pw.println();
pw.println("The test commands for simulated providers are:");
@@ -132,6 +171,119 @@ class LocationTimeZoneManagerShellCommand extends ShellCommand {
return 0;
}
+ private int runSetProviderModeOverride() {
+ PrintWriter outPrintWriter = getOutPrintWriter();
+ try {
+ String providerName = getNextArgRequired();
+ String modeOverride = getNextArgRequired();
+ outPrintWriter.println("Setting provider mode override for " + providerName
+ + " to " + modeOverride);
+ mService.setProviderModeOverride(providerName, modeOverride);
+ } catch (RuntimeException e) {
+ reportError(e);
+ return 1;
+ }
+ return 0;
+ }
+
+ private int runRecordProviderStates() {
+ PrintWriter outPrintWriter = getOutPrintWriter();
+ boolean enabled;
+ try {
+ String nextArg = getNextArgRequired();
+ enabled = Boolean.parseBoolean(nextArg);
+ } catch (RuntimeException e) {
+ reportError(e);
+ return 1;
+ }
+
+ outPrintWriter.println("Setting provider state recording to " + enabled);
+ try {
+ mService.setProviderStateRecordingEnabled(enabled);
+ } catch (IllegalStateException e) {
+ reportError(e);
+ return 2;
+ }
+ return 0;
+ }
+
+ private int runDumpControllerState() {
+ LocationTimeZoneManagerServiceState state;
+ try {
+ state = mService.getStateForTests();
+ } catch (RuntimeException e) {
+ reportError(e);
+ return 1;
+ }
+
+ DualDumpOutputStream outputStream;
+ boolean useProto = Objects.equals(DUMP_STATE_OPTION_PROTO, getNextOption());
+ if (useProto) {
+ FileDescriptor outFd = getOutFileDescriptor();
+ outputStream = new DualDumpOutputStream(new ProtoOutputStream(outFd));
+ } else {
+ outputStream = new DualDumpOutputStream(
+ new IndentingPrintWriter(getOutPrintWriter(), " "));
+ }
+ if (state.getLastSuggestion() != null) {
+ GeolocationTimeZoneSuggestion lastSuggestion = state.getLastSuggestion();
+ long lastSuggestionToken = outputStream.start(
+ "last_suggestion", LocationTimeZoneManagerServiceStateProto.LAST_SUGGESTION);
+ for (String zoneId : lastSuggestion.getZoneIds()) {
+ outputStream.write(
+ "zone_ids" , GeolocationTimeZoneSuggestionProto.ZONE_IDS, zoneId);
+ }
+ for (String debugInfo : lastSuggestion.getDebugInfo()) {
+ outputStream.write(
+ "debug_info", GeolocationTimeZoneSuggestionProto.DEBUG_INFO, debugInfo);
+ }
+ outputStream.end(lastSuggestionToken);
+ }
+
+ writeProviderStates(outputStream, state.getPrimaryProviderStates(),
+ "primary_provider_states",
+ LocationTimeZoneManagerServiceStateProto.PRIMARY_PROVIDER_STATES);
+ writeProviderStates(outputStream, state.getSecondaryProviderStates(),
+ "secondary_provider_states",
+ LocationTimeZoneManagerServiceStateProto.SECONDARY_PROVIDER_STATES);
+ outputStream.flush();
+
+ return 0;
+ }
+
+ private static void writeProviderStates(DualDumpOutputStream outputStream,
+ List<LocationTimeZoneProvider.ProviderState> providerStates, String fieldName,
+ long fieldId) {
+ for (LocationTimeZoneProvider.ProviderState providerState : providerStates) {
+ long providerStateToken = outputStream.start(fieldName, fieldId);
+ outputStream.write("state", TimeZoneProviderStateProto.STATE,
+ convertProviderStateEnumToProtoEnum(providerState.stateEnum));
+ outputStream.end(providerStateToken);
+ }
+ }
+
+ private static int convertProviderStateEnumToProtoEnum(@ProviderStateEnum int stateEnum) {
+ switch (stateEnum) {
+ case PROVIDER_STATE_UNKNOWN:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_UNKNOWN;
+ case PROVIDER_STATE_STARTED_INITIALIZING:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_INITIALIZING;
+ case PROVIDER_STATE_STARTED_CERTAIN:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_CERTAIN;
+ case PROVIDER_STATE_STARTED_UNCERTAIN:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_UNCERTAIN;
+ case PROVIDER_STATE_STOPPED:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_DISABLED;
+ case PROVIDER_STATE_PERM_FAILED:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_PERM_FAILED;
+ case PROVIDER_STATE_DESTROYED:
+ return LocationTimeZoneManagerProto.TIME_ZONE_PROVIDER_STATE_DESTROYED;
+ default: {
+ throw new IllegalArgumentException("Unknown stateEnum=" + stateEnum);
+ }
+ }
+ }
+
private int runSendProviderTestCommand() {
PrintWriter outPrintWriter = getOutPrintWriter();
diff --git a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
index 132c1671f725..9a7b7750659c 100644
--- a/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/LocationTimeZoneProvider.java
@@ -49,6 +49,8 @@ import com.android.server.timezonedetector.Dumpable;
import com.android.server.timezonedetector.ReferenceWithHistory;
import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
@@ -339,11 +341,20 @@ abstract class LocationTimeZoneProvider implements Dumpable {
@NonNull final String mProviderName;
/**
+ * Usually {@code false} but can be set to {@code true} for testing.
+ */
+ @GuardedBy("mSharedLock")
+ private boolean mStateChangeRecording;
+
+ @GuardedBy("mSharedLock")
+ @NonNull
+ private final ArrayList<ProviderState> mRecordedStates = new ArrayList<>(0);
+
+ /**
* The current state (with history for debugging).
*/
@GuardedBy("mSharedLock")
- final ReferenceWithHistory<ProviderState> mCurrentState =
- new ReferenceWithHistory<>(10);
+ final ReferenceWithHistory<ProviderState> mCurrentState = new ReferenceWithHistory<>(10);
/**
* Used for scheduling initialization timeouts, i.e. for providers that have just been started.
@@ -423,6 +434,28 @@ abstract class LocationTimeZoneProvider implements Dumpable {
abstract void onDestroy();
/**
+ * Sets the provider into state recording mode for tests.
+ */
+ final void setStateChangeRecordingEnabled(boolean enabled) {
+ mThreadingDomain.assertCurrentThread();
+ synchronized (mSharedLock) {
+ mStateChangeRecording = enabled;
+ mRecordedStates.clear();
+ mRecordedStates.trimToSize();
+ }
+ }
+
+ /**
+ * Returns recorded states.
+ */
+ final List<ProviderState> getRecordedStates() {
+ mThreadingDomain.assertCurrentThread();
+ synchronized (mSharedLock) {
+ return new ArrayList<>(mRecordedStates);
+ }
+ }
+
+ /**
* Set the current state, for use by this class and subclasses only. If {@code #notifyChanges}
* is {@code true} and {@code newState} is not equal to the old state, then {@link
* ProviderListener#onProviderStateChange(ProviderState)} must be called on
@@ -434,8 +467,11 @@ abstract class LocationTimeZoneProvider implements Dumpable {
ProviderState oldState = mCurrentState.get();
mCurrentState.set(newState);
onSetCurrentState(newState);
- if (notifyChanges) {
- if (!Objects.equals(newState, oldState)) {
+ if (!Objects.equals(newState, oldState)) {
+ if (mStateChangeRecording) {
+ mRecordedStates.add(newState);
+ }
+ if (notifyChanges) {
mProviderListener.onProviderStateChange(newState);
}
}
diff --git a/services/core/java/com/android/server/media/MediaShellCommand.java b/services/core/java/com/android/server/media/MediaShellCommand.java
index 69c57a9a5d74..103cdd997efc 100644
--- a/services/core/java/com/android/server/media/MediaShellCommand.java
+++ b/services/core/java/com/android/server/media/MediaShellCommand.java
@@ -67,7 +67,7 @@ public class MediaShellCommand extends ShellCommand {
}
if (sThread == null) {
Looper.prepare();
- sThread = ActivityThread.systemMain();
+ sThread = ActivityThread.currentActivityThread();
Context context = sThread.getSystemContext();
sMediaSessionManager =
(MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index 2326ad39fd27..bce80696f72c 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -20,8 +20,8 @@ import android.net.NetworkIdentity;
import android.service.NetworkIdentitySetProto;
import android.util.proto.ProtoOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
import java.io.IOException;
import java.util.HashSet;
@@ -44,7 +44,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
public NetworkIdentitySet() {
}
- public NetworkIdentitySet(DataInputStream in) throws IOException {
+ public NetworkIdentitySet(DataInput in) throws IOException {
final int version = in.readInt();
final int size = in.readInt();
for (int i = 0; i < size; i++) {
@@ -89,7 +89,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
}
}
- public void writeToStream(DataOutputStream out) throws IOException {
+ public void writeToStream(DataOutput out) throws IOException {
out.writeInt(VERSION_ADD_DEFAULT_NETWORK);
out.writeInt(size());
for (NetworkIdentity ident : this) {
@@ -143,7 +143,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
return true;
}
- private static void writeOptionalString(DataOutputStream out, String value) throws IOException {
+ private static void writeOptionalString(DataOutput out, String value) throws IOException {
if (value != null) {
out.writeByte(1);
out.writeUTF(value);
@@ -152,7 +152,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements
}
}
- private static String readOptionalString(DataInputStream in) throws IOException {
+ private static String readOptionalString(DataInput in) throws IOException {
if (in.readByte() != 0) {
return in.readUTF();
} else {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index c4beddd42eaf..6aefe41891f9 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -63,12 +63,15 @@ import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import java.io.BufferedInputStream;
+import java.io.DataInput;
import java.io.DataInputStream;
+import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ProtocolException;
import java.time.ZonedDateTime;
@@ -82,7 +85,7 @@ import java.util.Objects;
* Collection of {@link NetworkStatsHistory}, stored based on combined key of
* {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
*/
-public class NetworkStatsCollection implements FileRotator.Reader {
+public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer {
/** File header magic number: "ANET" */
private static final int FILE_MAGIC = 0x414E4554;
@@ -431,10 +434,10 @@ public class NetworkStatsCollection implements FileRotator.Reader {
@Override
public void read(InputStream in) throws IOException {
- read(new DataInputStream(in));
+ read((DataInput) new DataInputStream(in));
}
- public void read(DataInputStream in) throws IOException {
+ private void read(DataInput in) throws IOException {
// verify file magic header intact
final int magic = in.readInt();
if (magic != FILE_MAGIC) {
@@ -468,7 +471,13 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
}
- public void write(DataOutputStream out) throws IOException {
+ @Override
+ public void write(OutputStream out) throws IOException {
+ write((DataOutput) new DataOutputStream(out));
+ out.flush();
+ }
+
+ private void write(DataOutput out) throws IOException {
// cluster key lists grouped by ident
final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
for (Key key : mStats.keySet()) {
@@ -497,8 +506,6 @@ public class NetworkStatsCollection implements FileRotator.Reader {
history.writeToStream(out);
}
}
-
- out.flush();
}
@Deprecated
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index ce741693cb4b..978ae87d39d5 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -42,7 +42,6 @@ import com.google.android.collect.Sets;
import libcore.io.IoUtils;
import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -375,7 +374,7 @@ public class NetworkStatsRecorder {
@Override
public void write(OutputStream out) throws IOException {
- mCollection.write(new DataOutputStream(out));
+ mCollection.write(out);
mCollection.reset();
}
}
@@ -412,7 +411,7 @@ public class NetworkStatsRecorder {
@Override
public void write(OutputStream out) throws IOException {
- mTemp.write(new DataOutputStream(out));
+ mTemp.write(out);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c10655896ec3..cc5dfdceb07d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -68,6 +68,7 @@ import static android.os.UserHandle.USER_NULL;
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
@@ -9497,7 +9498,7 @@ public class NotificationManagerService extends SystemService {
public class NotificationListeners extends ManagedServices {
static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
- static final String TAG_REQUESTED_LISTENERS = "requested_listeners";
+ static final String TAG_REQUESTED_LISTENERS = "req_listeners";
static final String TAG_REQUESTED_LISTENER = "listener";
static final String ATT_COMPONENT = "component";
static final String ATT_TYPES = "types";
@@ -9686,7 +9687,7 @@ public class NotificationManagerService extends SystemService {
final ComponentName cn = ComponentName.unflattenFromString(
XmlUtils.readStringAttribute(parser, ATT_COMPONENT));
int approved = FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ALERTING
- | FLAG_FILTER_TYPE_SILENT;
+ | FLAG_FILTER_TYPE_SILENT | FLAG_FILTER_TYPE_ONGOING;
ArraySet<String> disallowedPkgs = new ArraySet<>();
final int listenerOuterDepth = parser.getDepth();
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 094be0622bab..f8990c065341 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -167,6 +167,7 @@ public class AppsFilter implements Watchable, Snappable {
*
* @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
*/
+ @Override
public void registerObserver(@NonNull Watcher observer) {
mWatchable.registerObserver(observer);
}
@@ -177,17 +178,29 @@ public class AppsFilter implements Watchable, Snappable {
*
* @param observer The {@link Watcher} that should not be in the notification list.
*/
+ @Override
public void unregisterObserver(@NonNull Watcher observer) {
mWatchable.unregisterObserver(observer);
}
/**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
+
+ /**
* Invokes {@link Watcher#onChange} on each registered observer. The method can be called
* with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
* is generally the first (deepest) {@link Watchable} to detect a change.
*
* @param what The {@link Watchable} that generated the event.
*/
+ @Override
public void dispatchChange(@Nullable Watchable what) {
mSnapshot = null;
mWatchable.dispatchChange(what);
@@ -443,7 +456,7 @@ public class AppsFilter implements Watchable, Snappable {
}
final StateProvider stateProvider = command -> {
synchronized (injector.getLock()) {
- command.currentState(injector.getSettings().getPackagesLocked().untrackedMap(),
+ command.currentState(injector.getSettings().getPackagesLocked().untrackedStorage(),
injector.getUserManagerInternal().getUserInfos());
}
};
@@ -979,7 +992,7 @@ public class AppsFilter implements Watchable, Snappable {
@Nullable
SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users,
WatchedArrayMap<String, PackageSetting> existingSettings) {
- return getVisibilityAllowList(setting, users, existingSettings.untrackedMap());
+ return getVisibilityAllowList(setting, users, existingSettings.untrackedStorage());
}
/**
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index bf7f466457e9..aae6ce46de66 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -19,8 +19,8 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.content.IntentFilter;
+import com.android.server.WatchableIntentResolver;
import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
import java.util.List;
@@ -57,7 +57,7 @@ class CrossProfileIntentResolver
*/
public CrossProfileIntentResolver snapshot() {
CrossProfileIntentResolver result = new CrossProfileIntentResolver();
- result.doCopy(this);
+ result.copyFrom(this);
return result;
}
}
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 69d3e5c2f941..c3bca285dca3 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -154,6 +154,9 @@ class InstantAppRegistry implements Watchable, Snappable {
public void unregisterObserver(@NonNull Watcher observer) {
mWatchable.unregisterObserver(observer);
}
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
public void dispatchChange(@Nullable Watchable what) {
mSnapshot = null;
mWatchable.dispatchChange(what);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index d0f9787bacb8..c1bfcac50772 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,8 +19,8 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.content.IntentFilter;
+import com.android.server.WatchableIntentResolver;
import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
public class PersistentPreferredIntentResolver
extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
@@ -47,7 +47,7 @@ public class PersistentPreferredIntentResolver
*/
public PersistentPreferredIntentResolver snapshot() {
PersistentPreferredIntentResolver result = new PersistentPreferredIntentResolver();
- result.doCopy(this);
+ result.copyFrom(this);
return result;
}
}
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index b62421e31361..0e3b85ca677a 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,8 +19,8 @@ package com.android.server.pm;
import android.annotation.NonNull;
import android.content.IntentFilter;
+import com.android.server.WatchableIntentResolver;
import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -76,7 +76,7 @@ public class PreferredIntentResolver
*/
public PreferredIntentResolver snapshot() {
PreferredIntentResolver result = new PreferredIntentResolver();
- result.doCopy(this);
+ result.copyFrom(this);
return result;
}
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 7924d5d48876..0e8a278f3b6b 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -49,6 +49,7 @@ public abstract class SettingBase implements Watchable {
*
* @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
*/
+ @Override
public void registerObserver(@NonNull Watcher observer) {
mWatchable.registerObserver(observer);
}
@@ -59,20 +60,33 @@ public abstract class SettingBase implements Watchable {
*
* @param observer The {@link Watcher} that should not be in the notification list.
*/
+ @Override
public void unregisterObserver(@NonNull Watcher observer) {
mWatchable.unregisterObserver(observer);
}
/**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
+
+ /**
* Invokes {@link Watcher#onChange} on each registered observer. The method can be called
* with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
* is generally the first (deepest) {@link Watchable} to detect a change.
*
* @param what The {@link Watchable} that generated the event.
*/
+ @Override
public void dispatchChange(@Nullable Watchable what) {
mWatchable.dispatchChange(what);
}
+
/**
* Notify listeners that this object has changed.
*/
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7c4dadea89eb..50c1065a6000 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -115,12 +115,15 @@ import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
import com.android.server.utils.Snappable;
-import com.android.server.utils.Snapshots;
import com.android.server.utils.TimingsTraceAndSlog;
import com.android.server.utils.Watchable;
import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watched;
+import com.android.server.utils.WatchedArrayList;
import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedArraySet;
import com.android.server.utils.WatchedSparseArray;
+import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
import libcore.io.IoUtils;
@@ -189,6 +192,16 @@ public final class Settings implements Watchable, Snappable {
}
/**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ return mWatchable.isRegisteredObserver(observer);
+ }
+
+ /**
* Invokes {@link Watcher#onChange} on each registered observer. The method can be called
* with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
* is generally the first (deepest) {@link Watchable} to detect a change.
@@ -350,6 +363,7 @@ public final class Settings implements Watchable, Snappable {
private final File mKernelMappingFilename;
/** Map from package name to settings */
+ @Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
final WatchedArrayMap<String, PackageSetting> mPackages = new WatchedArrayMap<>();
@@ -357,21 +371,29 @@ public final class Settings implements Watchable, Snappable {
* List of packages that were involved in installing other packages, i.e. are listed
* in at least one app's InstallSource.
*/
- private final ArraySet<String> mInstallerPackages = new ArraySet<>();
+ @Watched
+ private final WatchedArraySet<String> mInstallerPackages = new WatchedArraySet<>();
/** Map from package name to appId and excluded userids */
- private final ArrayMap<String, KernelPackageState> mKernelMapping = new ArrayMap<>();
+ @Watched
+ private final WatchedArrayMap<String, KernelPackageState> mKernelMapping =
+ new WatchedArrayMap<>();
// List of replaced system applications
+ @Watched
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
- final ArrayMap<String, PackageSetting> mDisabledSysPackages = new ArrayMap<>();
+ final WatchedArrayMap<String, PackageSetting> mDisabledSysPackages = new WatchedArrayMap<>();
/** List of packages that are blocked for uninstall for specific users */
- private final SparseArray<ArraySet<String>> mBlockUninstallPackages = new SparseArray<>();
+ @Watched
+ private final WatchedSparseArray<ArraySet<String>> mBlockUninstallPackages =
+ new WatchedSparseArray<>();
// Set of restored intent-filter verification states
- private final ArrayMap<String, IntentFilterVerificationInfo> mRestoredIntentFilterVerifications =
- new ArrayMap<String, IntentFilterVerificationInfo>();
+ @Watched
+ private final WatchedArrayMap<String, IntentFilterVerificationInfo>
+ mRestoredIntentFilterVerifications =
+ new WatchedArrayMap<String, IntentFilterVerificationInfo>();
private static final class KernelPackageState {
int appId;
@@ -381,7 +403,8 @@ public final class Settings implements Watchable, Snappable {
private static int mFirstAvailableUid = 0;
/** Map from volume UUID to {@link VersionInfo} */
- private ArrayMap<String, VersionInfo> mVersion = new ArrayMap<>();
+ @Watched
+ private WatchedArrayMap<String, VersionInfo> mVersion = new WatchedArrayMap<>();
/**
* Version details for a storage volume that may hold apps.
@@ -423,21 +446,27 @@ public final class Settings implements Watchable, Snappable {
// The user's preferred activities associated with particular intent
// filters.
+ @Watched
private final WatchedSparseArray<PreferredIntentResolver>
mPreferredActivities = new WatchedSparseArray<>();
// The persistent preferred activities of the user's profile/device owner
// associated with particular intent filters.
+ @Watched
private final WatchedSparseArray<PersistentPreferredIntentResolver>
mPersistentPreferredActivities = new WatchedSparseArray<>();
// For every user, it is used to find to which other users the intent can be forwarded.
+ @Watched
private final WatchedSparseArray<CrossProfileIntentResolver>
mCrossProfileIntentResolvers = new WatchedSparseArray<>();
- final ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<>();
- private final ArrayList<SettingBase> mAppIds;
- private final SparseArray<SettingBase> mOtherAppIds;
+ @Watched
+ final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
+ @Watched
+ private final WatchedArrayList<SettingBase> mAppIds;
+ @Watched
+ private final WatchedSparseArray<SettingBase> mOtherAppIds;
// For reading/writing settings file.
private final ArrayList<Signature> mPastSignatures =
@@ -449,13 +478,17 @@ public final class Settings implements Watchable, Snappable {
// Keys are the new names of the packages, values are the original
// names. The packages appear everywhere else under their original
// names.
- private final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
+ @Watched
+ private final WatchedArrayMap<String, String> mRenamedPackages =
+ new WatchedArrayMap<String, String>();
// For every user, it is used to find the package name of the default Browser App.
- final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
+ @Watched
+ final WatchedSparseArray<String> mDefaultBrowserApp = new WatchedSparseArray<String>();
// App-link priority tracking, per-user
- final SparseIntArray mNextAppLinkGeneration = new SparseIntArray();
+ @Watched
+ final WatchedSparseIntArray mNextAppLinkGeneration = new WatchedSparseIntArray();
final StringBuilder mReadMessages = new StringBuilder();
@@ -471,7 +504,7 @@ public final class Settings implements Watchable, Snappable {
private final File mSystemDir;
public final KeySetManagerService mKeySetManagerService =
- new KeySetManagerService(mPackages.untrackedMap());
+ new KeySetManagerService(mPackages.untrackedStorage());
/** Settings and other information about permissions */
final LegacyPermissionSettings mPermissions;
@@ -492,8 +525,8 @@ public final class Settings implements Watchable, Snappable {
public Settings(Map<String, PackageSetting> pkgSettings) {
mLock = new Object();
mPackages.putAll(pkgSettings);
- mAppIds = new ArrayList<>();
- mOtherAppIds = new SparseArray<>();
+ mAppIds = new WatchedArrayList<>();
+ mOtherAppIds = new WatchedSparseArray<>();
mSystemDir = null;
mPermissions = null;
mRuntimePermissionsPersistence = null;
@@ -504,17 +537,32 @@ public final class Settings implements Watchable, Snappable {
mStoppedPackagesFilename = null;
mBackupStoppedPackagesFilename = null;
mKernelMappingFilename = null;
+
mPackages.registerObserver(mObserver);
+ mInstallerPackages.registerObserver(mObserver);
+ mKernelMapping.registerObserver(mObserver);
+ mDisabledSysPackages.registerObserver(mObserver);
+ mBlockUninstallPackages.registerObserver(mObserver);
+ mRestoredIntentFilterVerifications.registerObserver(mObserver);
+ mVersion.registerObserver(mObserver);
mPreferredActivities.registerObserver(mObserver);
mPersistentPreferredActivities.registerObserver(mObserver);
mCrossProfileIntentResolvers.registerObserver(mObserver);
+ mSharedUsers.registerObserver(mObserver);
+ mAppIds.registerObserver(mObserver);
+ mOtherAppIds.registerObserver(mObserver);
+ mRenamedPackages.registerObserver(mObserver);
+ mDefaultBrowserApp.registerObserver(mObserver);
+ mNextAppLinkGeneration.registerObserver(mObserver);
+
+ Watchable.verifyWatchedAttributes(this, mObserver);
}
Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
LegacyPermissionDataProvider permissionDataProvider, Object lock) {
mLock = lock;
- mAppIds = new ArrayList<>();
- mOtherAppIds = new SparseArray<>();
+ mAppIds = new WatchedArrayList<>();
+ mOtherAppIds = new WatchedSparseArray<>();
mPermissions = new LegacyPermissionSettings(lock);
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
runtimePermissionsPersistence);
@@ -537,10 +585,25 @@ public final class Settings implements Watchable, Snappable {
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
+
mPackages.registerObserver(mObserver);
+ mInstallerPackages.registerObserver(mObserver);
+ mKernelMapping.registerObserver(mObserver);
+ mDisabledSysPackages.registerObserver(mObserver);
+ mBlockUninstallPackages.registerObserver(mObserver);
+ mRestoredIntentFilterVerifications.registerObserver(mObserver);
+ mVersion.registerObserver(mObserver);
mPreferredActivities.registerObserver(mObserver);
mPersistentPreferredActivities.registerObserver(mObserver);
mCrossProfileIntentResolvers.registerObserver(mObserver);
+ mSharedUsers.registerObserver(mObserver);
+ mAppIds.registerObserver(mObserver);
+ mOtherAppIds.registerObserver(mObserver);
+ mRenamedPackages.registerObserver(mObserver);
+ mDefaultBrowserApp.registerObserver(mObserver);
+ mNextAppLinkGeneration.registerObserver(mObserver);
+
+ Watchable.verifyWatchedAttributes(this, mObserver);
}
/**
@@ -568,7 +631,7 @@ public final class Settings implements Watchable, Snappable {
mInstallerPackages.addAll(r.mInstallerPackages);
mKernelMapping.putAll(r.mKernelMapping);
mDisabledSysPackages.putAll(r.mDisabledSysPackages);
- Snapshots.copy(mBlockUninstallPackages, r.mBlockUninstallPackages);
+ mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages);
mRestoredIntentFilterVerifications.putAll(r.mRestoredIntentFilterVerifications);
mVersion.putAll(r.mVersion);
mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
@@ -579,13 +642,13 @@ public final class Settings implements Watchable, Snappable {
WatchedSparseArray.snapshot(
mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
mSharedUsers.putAll(r.mSharedUsers);
- mAppIds = new ArrayList<>(r.mAppIds);
- mOtherAppIds = r.mOtherAppIds.clone();
+ mAppIds = r.mAppIds.snapshot();
+ mOtherAppIds = r.mOtherAppIds.snapshot();
mPastSignatures.addAll(r.mPastSignatures);
mKeySetRefs.putAll(r.mKeySetRefs);
- mRenamedPackages.putAll(r.mRenamedPackages);
- Snapshots.copy(mDefaultBrowserApp, r.mDefaultBrowserApp);
- Snapshots.snapshot(mNextAppLinkGeneration, r.mNextAppLinkGeneration);
+ mRenamedPackages.snapshot(r.mRenamedPackages);
+ mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp);
+ mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
// mReadMessages
mPendingPackages.addAll(r.mPendingPackages);
mSystemDir = null;
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 033bfa648f2f..865571e90338 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -25,6 +25,7 @@ import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.content.Context;
+import android.location.LocationManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -311,6 +312,19 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
mHandler.post(() -> mTimeZoneDetectorStrategy.suggestTelephonyTimeZone(timeZoneSuggestion));
}
+ boolean isGeoTimeZoneDetectionSupported() {
+ enforceManageTimeZoneDetectorPermission();
+
+ return isGeoLocationTimeZoneDetectionEnabled(mContext);
+ }
+
+ boolean isLocationEnabled() {
+ enforceManageTimeZoneDetectorPermission();
+
+ return mContext.getSystemService(LocationManager.class)
+ .isLocationEnabledForUser(mContext.getUser());
+ }
+
@Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
@Nullable String[] args) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index 13b44566c66d..b2630300a6aa 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -15,10 +15,17 @@
*/
package com.android.server.timezonedetector;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_IS_LOCATION_ENABLED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED;
+import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SET_GEO_DETECTION_ENABLED;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE;
import static android.app.timezonedetector.TimeZoneDetector.SHELL_COMMAND_SUGGEST_TELEPHONY_TIME_ZONE;
+import android.app.time.TimeZoneConfiguration;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
import android.app.timezonedetector.TelephonyTimeZoneSuggestion;
import android.os.ShellCommand;
@@ -43,6 +50,18 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
}
switch (cmd) {
+ case SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED:
+ return runIsAutoDetectionEnabled();
+ case SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED:
+ return runSetAutoDetectionEnabled();
+ case SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED:
+ return runIsGeoDetectionSupported();
+ case SHELL_COMMAND_IS_LOCATION_ENABLED:
+ return runIsLocationEnabled();
+ case SHELL_COMMAND_IS_GEO_DETECTION_ENABLED:
+ return runIsGeoDetectionEnabled();
+ case SHELL_COMMAND_SET_GEO_DETECTION_ENABLED:
+ return runSetGeoDetectionEnabled();
case SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE:
return runSuggestGeolocationTimeZone();
case SHELL_COMMAND_SUGGEST_MANUAL_TIME_ZONE:
@@ -55,6 +74,54 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
}
}
+ private int runIsAutoDetectionEnabled() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enabled = mInterface.getCapabilitiesAndConfig()
+ .getConfiguration()
+ .isAutoDetectionEnabled();
+ pw.println(enabled);
+ return 0;
+ }
+
+ private int runIsGeoDetectionSupported() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enabled = mInterface.isGeoTimeZoneDetectionSupported();
+ pw.println(enabled);
+ return 0;
+ }
+
+ private int runIsLocationEnabled() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enabled = mInterface.isLocationEnabled();
+ pw.println(enabled);
+ return 0;
+ }
+
+ private int runIsGeoDetectionEnabled() {
+ final PrintWriter pw = getOutPrintWriter();
+ boolean enabled = mInterface.getCapabilitiesAndConfig()
+ .getConfiguration()
+ .isGeoDetectionEnabled();
+ pw.println(enabled);
+ return 0;
+ }
+
+ private int runSetAutoDetectionEnabled() {
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
+ .setAutoDetectionEnabled(enabled)
+ .build();
+ return mInterface.updateConfiguration(configuration) ? 0 : 1;
+ }
+
+ private int runSetGeoDetectionEnabled() {
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ TimeZoneConfiguration configuration = new TimeZoneConfiguration.Builder()
+ .setGeoDetectionEnabled(enabled)
+ .build();
+ return mInterface.updateConfiguration(configuration) ? 0 : 1;
+ }
+
private int runSuggestGeolocationTimeZone() {
return runSuggestTimeZone(
() -> GeolocationTimeZoneSuggestion.parseCommandLineArg(this),
@@ -96,6 +163,20 @@ class TimeZoneDetectorShellCommand extends ShellCommand {
pw.println("Time Zone Detector (time_zone_detector) commands:");
pw.println(" help");
pw.println(" Print this help text.");
+ pw.printf(" %s\n", SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED);
+ pw.println(" Prints true/false according to the automatic tz detection setting");
+ pw.printf(" %s true|false\n", SHELL_COMMAND_SET_AUTO_DETECTION_ENABLED);
+ pw.println(" Sets the automatic tz detection setting.");
+ pw.printf(" %s\n", SHELL_COMMAND_IS_GEO_DETECTION_SUPPORTED);
+ pw.println(" Prints true/false according to whether geolocation time zone detection is"
+ + " supported on this device");
+ pw.printf(" %s\n", SHELL_COMMAND_IS_LOCATION_ENABLED);
+ pw.println(" Prints true/false according to whether the master location toggle is"
+ + " enabled for the current user");
+ pw.printf(" %s\n", SHELL_COMMAND_IS_GEO_DETECTION_ENABLED);
+ pw.println(" Prints true/false according to the geolocation tz detection setting");
+ pw.printf(" %s true|false\n", SHELL_COMMAND_SET_GEO_DETECTION_ENABLED);
+ pw.println(" Sets the geolocation tz detection setting.");
pw.printf(" %s <geolocation suggestion opts>\n",
SHELL_COMMAND_SUGGEST_GEO_LOCATION_TIME_ZONE);
pw.printf(" %s <manual suggestion opts>\n",
diff --git a/services/core/java/com/android/server/utils/Watchable.java b/services/core/java/com/android/server/utils/Watchable.java
index 7c99274f3df2..f936693bd621 100644
--- a/services/core/java/com/android/server/utils/Watchable.java
+++ b/services/core/java/com/android/server/utils/Watchable.java
@@ -18,6 +18,10 @@ package com.android.server.utils;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.Build;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
/**
* Notify registered {@link Watcher}s when the content changes.
@@ -41,6 +45,13 @@ public interface Watchable {
public void unregisterObserver(@NonNull Watcher observer);
/**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ public boolean isRegisteredObserver(@NonNull Watcher observer);
+
+ /**
* Invokes {@link Watcher#onChange} on each registered observer. The method can be called
* with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this
* is generally the first (deepest) {@link Watchable} to detect a change.
@@ -48,4 +59,42 @@ public interface Watchable {
* @param what The {@link Watchable} that generated the event.
*/
public void dispatchChange(@Nullable Watchable what);
+
+ /**
+ * Return true if the field is tagged with @Watched
+ */
+ private static boolean isWatched(Field f) {
+ for (Annotation a : f.getDeclaredAnnotations()) {
+ if (a.annotationType().equals(Watched.class)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Verify that all @Watched {@link Watchable} attributes are being watched by this
+ * class. This requires reflection and only runs in engineering or user debug
+ * builds.
+ */
+ static void verifyWatchedAttributes(Object base, Watcher observer) {
+ if (Build.IS_ENG || Build.IS_USERDEBUG) {
+ for (Field f : base.getClass().getDeclaredFields()) {
+ try {
+ final boolean flagged = isWatched(f);
+ final Object o = f.get(base);
+ final boolean watchable = o instanceof Watchable;
+ if (flagged && watchable) {
+ Watchable attr = (Watchable) f.get(base);
+ if (attr != null && !attr.isRegisteredObserver(observer)) {
+ throw new RuntimeException(f.getName() + " missing an observer");
+ }
+ }
+ } catch (IllegalAccessException e) {
+ // The field is protected; ignore it. Other exceptions that may be thrown by
+ // Field.get() are allowed to roll up.
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/utils/WatchableImpl.java b/services/core/java/com/android/server/utils/WatchableImpl.java
index 16400b186ab0..527db5402e74 100644
--- a/services/core/java/com/android/server/utils/WatchableImpl.java
+++ b/services/core/java/com/android/server/utils/WatchableImpl.java
@@ -66,6 +66,18 @@ public class WatchableImpl implements Watchable {
}
/**
+ * Return true if the {@link Watcher) is a registered observer.
+ * @param observer A {@link Watcher} that might be registered
+ * @return true if the observer is registered with this {@link Watchable}.
+ */
+ @Override
+ public boolean isRegisteredObserver(@NonNull Watcher observer) {
+ synchronized (mObservers) {
+ return mObservers.contains(observer);
+ }
+ }
+
+ /**
* Return the number of registered observers.
*
* @return The number of registered observers.
@@ -100,7 +112,7 @@ public class WatchableImpl implements Watchable {
/**
* Freeze the {@link Watchable}.
- **/
+ */
public void seal() {
synchronized (mObservers) {
mSealed = true;
diff --git a/services/core/java/com/android/server/utils/Watched.java b/services/core/java/com/android/server/utils/Watched.java
new file mode 100644
index 000000000000..4340d015119a
--- /dev/null
+++ b/services/core/java/com/android/server/utils/Watched.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation type to mark an attribute that is monitored for change detection and
+ * snapshot creation.
+ * TODO(b/176923052) Automate validation of @Watchable attributes.
+ */
+@Target({ ElementType.FIELD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Watched {
+}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayList.java b/services/core/java/com/android/server/utils/WatchedArrayList.java
new file mode 100644
index 000000000000..bb0ba1329d86
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedArrayList.java
@@ -0,0 +1,416 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * WatchedArrayMap is an {@link android.util.ArrayMap} that can report changes to itself. If its
+ * values are {@link Watchable} then the WatchedArrayMap will also report changes to the values.
+ * A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ * @param <E> The element type, stored in the array.
+ */
+public class WatchedArrayList<E> extends WatchableImpl
+ implements Snappable {
+
+ // The storage
+ private final ArrayList<E> mStorage;
+
+ // If true, the array is watching its children
+ private volatile boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ WatchedArrayList.this.dispatchChange(what);
+ }
+ };
+
+ /**
+ * A convenience function called when the elements are added to or removed from the storage.
+ * The watchable is always {@link this}.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed. Also note that if this is called with the same object
+ * twice, <this> is only registered once.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if the
+ * array is currently watching. This unconditionally removes the object from the
+ * registered list.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the
+ * array is currently watching, and if there are no other instances of this object in
+ * the storage. Note that the watching flag must be true if this function is to
+ * succeed. The object must already have been removed from the storage before this
+ * method is called.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (!mStorage.contains(o)) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.get(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.get(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Create a new empty {@link WatchedArrayList}. The default capacity of an array map
+ * is 0, and will grow once items are added to it.
+ */
+ public WatchedArrayList() {
+ this(0);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayList} with a given initial capacity.
+ */
+ public WatchedArrayList(int capacity) {
+ mStorage = new ArrayList<E>(capacity);
+ }
+
+ /**
+ * Create a new {@link WatchedArrayList} with the content of the collection.
+ */
+ public WatchedArrayList(@Nullable Collection<? extends E> c) {
+ mStorage = new ArrayList<E>();
+ if (c != null) {
+ // There is no need to register children because the WatchedArrayList starts
+ // life unobserved.
+ mStorage.addAll(c);
+ }
+ }
+
+ /**
+ * Create a {@link WatchedArrayList} from an {@link ArrayList}
+ */
+ public WatchedArrayList(@NonNull ArrayList<E> c) {
+ mStorage = new ArrayList<>(c);
+ }
+
+ /**
+ * Create a {@link WatchedArrayList} from an {@link WatchedArrayList}
+ */
+ public WatchedArrayList(@NonNull WatchedArrayList<E> c) {
+ mStorage = new ArrayList<>(c.mStorage);
+ }
+
+ /**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull ArrayList<E> src) {
+ clear();
+ final int end = src.size();
+ mStorage.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ add(src.get(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull ArrayList<E> dst) {
+ dst.clear();
+ final int end = size();
+ dst.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ dst.add(get(i));
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public ArrayList<E> untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
+ * Append the specified element to the end of the list
+ */
+ public boolean add(E value) {
+ final boolean result = mStorage.add(value);
+ registerChild(value);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * Insert the element into the list
+ */
+ public void add(int index, E value) {
+ mStorage.add(index, value);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * Append the elements of the collection to the list.
+ */
+ public boolean addAll(Collection<? extends E> c) {
+ if (c.size() > 0) {
+ for (E e: c) {
+ mStorage.add(e);
+ }
+ onChanged();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Insert the elements of the collection into the list at the index.
+ */
+ public boolean addAll(int index, Collection<? extends E> c) {
+ if (c.size() > 0) {
+ for (E e: c) {
+ mStorage.add(index++, e);
+ }
+ onChanged();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Remove all elements from the list.
+ */
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.get(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * Return true if the object is in the array.
+ */
+ public boolean contains(Object o) {
+ return mStorage.contains(o);
+ }
+
+ /**
+ * Ensure capacity.
+ */
+ public void ensureCapacity(int min) {
+ mStorage.ensureCapacity(min);
+ }
+
+ /**
+ * Retrieve the element at the specified index.
+ */
+ public E get(int index) {
+ return mStorage.get(index);
+ }
+
+ /**
+ * Return the index of the object. -1 is returned if the object is not in the list.
+ */
+ public int indexOf(Object o) {
+ return mStorage.indexOf(o);
+ }
+
+ /**
+ * True if the list has no elements
+ */
+ public boolean isEmpty() {
+ return mStorage.isEmpty();
+ }
+
+ /**
+ * Return the index of the last occurrence of the object.
+ */
+ public int lastIndexOf(Object o) {
+ return mStorage.lastIndexOf(o);
+ }
+
+ /**
+ * Remove and return the element at the specified position.
+ */
+ public E remove(int index) {
+ final E result = mStorage.remove(index);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * Remove the first occurrence of the object in the list. Return true if the object
+ * was actually in the list and false otherwise.
+ */
+ public boolean remove(Object o) {
+ if (mStorage.remove(o)) {
+ unregisterChildIf(o);
+ onChanged();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Replace the object at the index.
+ */
+ public E set(int index, E value) {
+ final E result = mStorage.set(index, value);
+ if (value != result) {
+ unregisterChildIf(result);
+ registerChild(value);
+ onChanged();
+ }
+ return result;
+ }
+
+ /**
+ * Return the number of elements in the list.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof WatchedArrayList) {
+ WatchedArrayList w = (WatchedArrayList) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedArrayList<E> snapshot() {
+ WatchedArrayList<E> l = new WatchedArrayList<>(size());
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedArrayList<E> r) {
+ snapshot(this, r);
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <E> void snapshot(@NonNull WatchedArrayList<E> dst,
+ @NonNull WatchedArrayList<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ dst.mStorage.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ final E val = Snapshots.maybeSnapshot(src.get(i));
+ dst.add(i, val);
+ }
+ dst.seal();
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
index e8065f140af7..7c1cde8502bd 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayMap.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -160,10 +160,48 @@ public class WatchedArrayMap<K, V> extends WatchableImpl
}
/**
+ * Create a {@link WatchedArrayMap} from an {@link ArrayMap}
+ */
+ public WatchedArrayMap(@NonNull ArrayMap<K, V> c) {
+ mStorage = new ArrayMap<>(c);
+ }
+
+ /**
+ * Create a {@link WatchedArrayMap} from an {@link WatchedArrayMap}
+ */
+ public WatchedArrayMap(@NonNull WatchedArrayMap<K, V> c) {
+ mStorage = new ArrayMap<>(c.mStorage);
+ }
+
+ /**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull ArrayMap<K, V> src) {
+ clear();
+ final int end = src.size();
+ mStorage.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull ArrayMap<K, V> dst) {
+ dst.clear();
+ final int end = size();
+ dst.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ dst.put(keyAt(i), valueAt(i));
+ }
+ }
+
+ /**
* Return the underlying storage. This breaks the wrapper but is necessary when
* passing the array to distant methods.
*/
- public ArrayMap untrackedMap() {
+ public ArrayMap<K, V> untrackedStorage() {
return mStorage;
}
@@ -213,7 +251,7 @@ public class WatchedArrayMap<K, V> extends WatchableImpl
* {@inheritDoc}
*/
@Override
- public boolean equals(Object o) {
+ public boolean equals(@Nullable Object o) {
if (o instanceof WatchedArrayMap) {
WatchedArrayMap w = (WatchedArrayMap) o;
return mStorage.equals(w.mStorage);
@@ -401,6 +439,15 @@ public class WatchedArrayMap<K, V> extends WatchableImpl
}
/**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedArrayMap<K, V> r) {
+ snapshot(this, r);
+ }
+
+ /**
* Make the destination a copy of the source. If the element is a subclass of Snapper then the
* copy contains snapshots of the elements. Otherwise the copy contains references to the
* elements. The destination must be initially empty. Upon return, the destination is
@@ -414,6 +461,7 @@ public class WatchedArrayMap<K, V> extends WatchableImpl
throw new IllegalArgumentException("snapshot destination is not empty");
}
final int end = src.size();
+ dst.mStorage.ensureCapacity(end);
for (int i = 0; i < end; i++) {
final V val = Snapshots.maybeSnapshot(src.valueAt(i));
final K key = src.keyAt(i);
diff --git a/services/core/java/com/android/server/utils/WatchedArraySet.java b/services/core/java/com/android/server/utils/WatchedArraySet.java
new file mode 100644
index 000000000000..5070dd1675d3
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedArraySet.java
@@ -0,0 +1,434 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArraySet;
+
+/**
+ * WatchedArraySet is an {@link android.util.ArraySet} that can report changes to itself. If its
+ * values are {@link Watchable} then the WatchedArraySet will also report changes to the values.
+ * A {@link Watchable} is notified only once, no matter how many times it is stored in the array.
+ * @param <E> The element type
+ */
+public class WatchedArraySet<E> extends WatchableImpl
+ implements Snappable {
+
+ // The storage
+ private final ArraySet<E> mStorage;
+
+ // If true, the array is watching its children
+ private volatile boolean mWatching = false;
+
+ // The local observer
+ private final Watcher mObserver = new Watcher() {
+ @Override
+ public void onChange(@Nullable Watchable what) {
+ WatchedArraySet.this.dispatchChange(what);
+ }
+ };
+
+ /**
+ * A convenience function called when the elements are added to or removed from the storage.
+ * The watchable is always {@link this}.
+ */
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * A convenience function. Register the object if it is {@link Watchable} and if the
+ * array is currently watching. Note that the watching flag must be true if this
+ * function is to succeed. Also note that if this is called with the same object
+ * twice, <this> is only registered once.
+ */
+ private void registerChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).registerObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable} and if the
+ * array is currently watching. This unconditionally removes the object from the
+ * registered list.
+ */
+ private void unregisterChild(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+
+ /**
+ * A convenience function. Unregister the object if it is {@link Watchable}, if the
+ * array is currently watching, and if there are no other instances of this object in
+ * the storage. Note that the watching flag must be true if this function is to
+ * succeed. The object must already have been removed from the storage before this
+ * method is called.
+ */
+ private void unregisterChildIf(Object o) {
+ if (mWatching && o instanceof Watchable) {
+ if (!mStorage.contains(o)) {
+ ((Watchable) o).unregisterObserver(mObserver);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Watcher} with the array. If this is the first Watcher than any
+ * array values that are {@link Watchable} are registered to the array itself.
+ */
+ @Override
+ public void registerObserver(@NonNull Watcher observer) {
+ super.registerObserver(observer);
+ if (registeredObserverCount() == 1) {
+ // The watching flag must be set true before any children are registered.
+ mWatching = true;
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ registerChild(mStorage.valueAt(i));
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Watcher} from the array. If this is the last Watcher than any
+ * array values that are {@link Watchable} are unregistered to the array itself.
+ */
+ @Override
+ public void unregisterObserver(@NonNull Watcher observer) {
+ super.unregisterObserver(observer);
+ if (registeredObserverCount() == 0) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ // The watching flag must be true while children are unregistered.
+ mWatching = false;
+ }
+ }
+
+ /**
+ * Create a new empty {@link WatchedArraySet}. The default capacity of an array map
+ * is 0, and will grow once items are added to it.
+ */
+ public WatchedArraySet() {
+ this(0, false);
+ }
+
+ /**
+ * Create a new {@link WatchedArraySet} with a given initial capacity.
+ */
+ public WatchedArraySet(int capacity) {
+ this(capacity, false);
+ }
+
+ /** {@hide} */
+ public WatchedArraySet(int capacity, boolean identityHashCode) {
+ mStorage = new ArraySet<E>(capacity, identityHashCode);
+ }
+
+ /**
+ * Create a new {@link WatchedArraySet} with items from the given array
+ */
+ public WatchedArraySet(@Nullable E[] array) {
+ mStorage = new ArraySet(array);
+ }
+
+ /**
+ * Create a {@link WatchedArraySet} from an {@link ArraySet}
+ */
+ public WatchedArraySet(@NonNull ArraySet<E> c) {
+ mStorage = new ArraySet<>(c);
+ }
+
+ /**
+ * Create a {@link WatchedArraySet} from an {@link WatchedArraySet}
+ */
+ public WatchedArraySet(@NonNull WatchedArraySet<E> c) {
+ mStorage = new ArraySet<>(c.mStorage);
+ }
+
+ /**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull ArraySet<E> src) {
+ clear();
+ final int end = src.size();
+ mStorage.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ add(src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull ArraySet<E> dst) {
+ dst.clear();
+ final int end = size();
+ dst.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ dst.add(valueAt(i));
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public ArraySet<E> untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
+ * Make the array map empty. All storage is released.
+ */
+ public void clear() {
+ // The storage cannot be simply cleared. Each element in the storage must be
+ // unregistered. Deregistration is only needed if the array is actually
+ // watching.
+ if (mWatching) {
+ final int end = mStorage.size();
+ for (int i = 0; i < end; i++) {
+ unregisterChild(mStorage.valueAt(i));
+ }
+ }
+ mStorage.clear();
+ onChanged();
+ }
+
+ /**
+ * Check whether a value exists in the set.
+ *
+ * @param key The value to search for.
+ * @return Returns true if the value exists, else false.
+ */
+ public boolean contains(Object key) {
+ return mStorage.contains(key);
+ }
+
+ /**
+ * Returns the index of a value in the set.
+ *
+ * @param key The value to search for.
+ * @return Returns the index of the value if it exists, else a negative integer.
+ */
+ public int indexOf(Object key) {
+ return mStorage.indexOf(key);
+ }
+
+ /**
+ * Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value stored at the given index.
+ */
+ public E valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Return true if the array map contains no items.
+ */
+ public boolean isEmpty() {
+ return mStorage.isEmpty();
+ }
+
+ /**
+ * Adds the specified object to this set. The set is not modified if it
+ * already contains the object.
+ *
+ * @param value the object to add.
+ * @return {@code true} if this set is modified, {@code false} otherwise.
+ */
+ public boolean add(E value) {
+ final boolean result = mStorage.add(value);
+ registerChild(value);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * Special fast path for appending items to the end of the array without validation.
+ * The array must already be large enough to contain the item.
+ * @hide
+ */
+ public void append(E value) {
+ mStorage.append(value);
+ registerChild(value);
+ onChanged();
+ }
+
+ /**
+ * Perform a {@link #add(Object)} of all values in <var>array</var>
+ * @param array The array whose contents are to be retrieved.
+ */
+ public void addAll(ArraySet<? extends E> array) {
+ final int end = array.size();
+ for (int i = 0; i < end; i++) {
+ add(array.valueAt(i));
+ }
+ }
+
+ /**
+ * Perform a {@link #add(Object)} of all values in <var>array</var>
+ * @param array The array whose contents are to be retrieved.
+ */
+ public void addAll(WatchedArraySet<? extends E> array) {
+ final int end = array.size();
+ for (int i = 0; i < end; i++) {
+ add(array.valueAt(i));
+ }
+ }
+
+ /**
+ * Removes the specified object from this set.
+ *
+ * @param o the object to remove.
+ * @return {@code true} if this set was modified, {@code false} otherwise.
+ */
+ public boolean remove(Object o) {
+ if (mStorage.remove(o)) {
+ unregisterChildIf(o);
+ onChanged();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, an
+ * {@link ArrayIndexOutOfBoundsException} is thrown.</p>
+ *
+ * @param index The desired index, must be between 0 and {@link #size()}-1.
+ * @return Returns the value that was stored at this index.
+ */
+ public E removeAt(int index) {
+ final E result = mStorage.removeAt(index);
+ unregisterChildIf(result);
+ onChanged();
+ return result;
+ }
+
+ /**
+ * Perform a {@link #remove(Object)} of all values in <var>array</var>
+ * @param array The array whose contents are to be removed.
+ */
+ public boolean removeAll(ArraySet<? extends E> array) {
+ final int end = array.size();
+ boolean any = false;
+ for (int i = 0; i < end; i++) {
+ any = remove(array.valueAt(i)) || any;
+ }
+ return any;
+ }
+
+ /**
+ * Return the number of items in this array map.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation returns false if the object is not a set, or
+ * if the sets have different sizes. Otherwise, for each value in this
+ * set, it checks to make sure the value also exists in the other set.
+ * If any value doesn't exist, the method returns false; otherwise, it
+ * returns true.
+ */
+ @Override
+ public boolean equals(@Nullable Object object) {
+ if (object instanceof WatchedArraySet) {
+ return mStorage.equals(((WatchedArraySet) object).mStorage);
+ } else {
+ return mStorage.equals(object);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation composes a string by iterating over its values. If
+ * this set contains itself as a value, the string "(this Set)"
+ * will appear in its place.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+
+ /**
+ * Create a copy of the array. If the element is a subclass of Snapper then the copy
+ * contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The returned snapshot is immutable.
+ * @return A new array whose elements are the elements of <this>.
+ */
+ public WatchedArraySet<E> snapshot() {
+ WatchedArraySet<E> l = new WatchedArraySet<>();
+ snapshot(l, this);
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedArraySet<E> r) {
+ snapshot(this, r);
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static <E> void snapshot(@NonNull WatchedArraySet<E> dst,
+ @NonNull WatchedArraySet<E> src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ dst.mStorage.ensureCapacity(end);
+ for (int i = 0; i < end; i++) {
+ final E val = Snapshots.maybeSnapshot(src.valueAt(i));
+ dst.append(val);
+ }
+ dst.seal();
+ }
+}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
index 6797c6eb7801..9b99b9176d19 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -143,6 +143,13 @@ public class WatchedSparseArray<E> extends WatchableImpl
}
/**
+ * Create a {@link WatchedSparseArray} from a {@link SparseArray}
+ */
+ public WatchedSparseArray(@NonNull SparseArray<E> c) {
+ mStorage = c.clone();
+ }
+
+ /**
* The copy constructor does not copy the watcher data.
*/
public WatchedSparseArray(@NonNull WatchedSparseArray<E> r) {
@@ -150,6 +157,36 @@ public class WatchedSparseArray<E> extends WatchableImpl
}
/**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull SparseArray<E> src) {
+ clear();
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull SparseArray<E> dst) {
+ dst.clear();
+ final int end = size();
+ for (int i = 0; i < end; i++) {
+ dst.put(keyAt(i), valueAt(i));
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public SparseArray<E> untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
* Returns true if the key exists in the array. This is equivalent to
* {@link #indexOfKey(int)} >= 0.
*
@@ -390,6 +427,21 @@ public class WatchedSparseArray<E> extends WatchableImpl
onChanged();
}
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof WatchedSparseArray) {
+ WatchedSparseArray w = (WatchedSparseArray) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
+ }
+
/**
* <p>This implementation composes a string by iterating over its mappings. If
* this map contains itself as a value, the string "(this Map)"
@@ -407,12 +459,21 @@ public class WatchedSparseArray<E> extends WatchableImpl
* @return A new array whose elements are the elements of <this>.
*/
public WatchedSparseArray<E> snapshot() {
- WatchedSparseArray<E> l = new WatchedSparseArray<>();
+ WatchedSparseArray<E> l = new WatchedSparseArray<>(size());
snapshot(l, this);
return l;
}
/**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedSparseArray<E> r) {
+ snapshot(this, r);
+ }
+
+ /**
* Make the destination a copy of the source. If the element is a subclass of Snapper then the
* copy contains snapshots of the elements. Otherwise the copy contains references to the
* elements. The destination must be initially empty. Upon return, the destination is
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
index b845eea168a5..772a8d07cffb 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -17,6 +17,7 @@
package com.android.server.utils;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.SparseBooleanArray;
/**
@@ -53,6 +54,13 @@ public class WatchedSparseBooleanArray extends WatchableImpl
}
/**
+ * Create a {@link WatchedSparseBooleanArray} from a {@link SparseBooleanArray}
+ */
+ public WatchedSparseBooleanArray(@NonNull SparseBooleanArray c) {
+ mStorage = c.clone();
+ }
+
+ /**
* The copy constructor does not copy the watcher data.
*/
public WatchedSparseBooleanArray(@NonNull WatchedSparseBooleanArray r) {
@@ -60,6 +68,36 @@ public class WatchedSparseBooleanArray extends WatchableImpl
}
/**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull SparseBooleanArray src) {
+ clear();
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull SparseBooleanArray dst) {
+ dst.clear();
+ final int end = size();
+ for (int i = 0; i < end; i++) {
+ dst.put(keyAt(i), valueAt(i));
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public SparseBooleanArray untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
* Gets the boolean mapped from the specified key, or <code>false</code>
* if no such mapping has been made.
*/
@@ -99,10 +137,10 @@ public class WatchedSparseBooleanArray extends WatchableImpl
* was one.
*/
public void put(int key, boolean value) {
- if (mStorage.get(key) != value) {
- mStorage.put(key, value);
- onChanged();
- }
+ // There is no fast way to know if the key exists with the input value, so this
+ // method always notifies change listeners.
+ mStorage.put(key, value);
+ onChanged();
}
/**
@@ -219,8 +257,13 @@ public class WatchedSparseBooleanArray extends WatchableImpl
}
@Override
- public boolean equals(Object that) {
- return this == that || mStorage.equals(that);
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof WatchedSparseBooleanArray) {
+ WatchedSparseBooleanArray w = (WatchedSparseBooleanArray) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
}
/**
@@ -249,13 +292,26 @@ public class WatchedSparseBooleanArray extends WatchableImpl
* @param r The source array, which is copied into <this>
*/
public void snapshot(@NonNull WatchedSparseBooleanArray r) {
- if (size() != 0) {
+ snapshot(this, r);
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static void snapshot(@NonNull WatchedSparseBooleanArray dst,
+ @NonNull WatchedSparseBooleanArray src) {
+ if (dst.size() != 0) {
throw new IllegalArgumentException("snapshot destination is not empty");
}
- final int end = r.size();
+ final int end = src.size();
for (int i = 0; i < end; i++) {
- put(r.keyAt(i), r.valueAt(i));
+ dst.put(src.keyAt(i), src.valueAt(i));
}
- seal();
+ dst.seal();
}
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseIntArray.java b/services/core/java/com/android/server/utils/WatchedSparseIntArray.java
new file mode 100644
index 000000000000..72705bf24199
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseIntArray.java
@@ -0,0 +1,323 @@
+/*
+ * 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.utils;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.SparseIntArray;
+
+/**
+ * A watched variant of SparseIntArray. Changes to the array are notified to
+ * registered {@link Watcher}s.
+ */
+public class WatchedSparseIntArray extends WatchableImpl
+ implements Snappable {
+
+ // The storage
+ private final SparseIntArray mStorage;
+
+ // A private convenience function
+ private void onChanged() {
+ dispatchChange(this);
+ }
+
+ /**
+ * Creates a new WatchedSparseIntArray containing no mappings.
+ */
+ public WatchedSparseIntArray() {
+ mStorage = new SparseIntArray();
+ }
+
+ /**
+ * Creates a new WatchedSparseIntArray containing no mappings that
+ * will not require any additional memory allocation to store the
+ * specified number of mappings. If you supply an initial capacity of
+ * 0, the sparse array will be initialized with a light-weight
+ * representation not requiring any additional array allocations.
+ */
+ public WatchedSparseIntArray(int initialCapacity) {
+ mStorage = new SparseIntArray(initialCapacity);
+ }
+
+ /**
+ * Create a {@link WatchedSparseIntArray} from a {@link SparseIntArray}
+ */
+ public WatchedSparseIntArray(@NonNull SparseIntArray c) {
+ mStorage = c.clone();
+ }
+
+ /**
+ * The copy constructor does not copy the watcher data.
+ */
+ public WatchedSparseIntArray(@NonNull WatchedSparseIntArray r) {
+ mStorage = r.mStorage.clone();
+ }
+
+ /**
+ * Make <this> a copy of src. Any data in <this> is discarded.
+ */
+ public void copyFrom(@NonNull SparseIntArray src) {
+ clear();
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ put(src.keyAt(i), src.valueAt(i));
+ }
+ }
+
+ /**
+ * Make dst a copy of <this>. Any previous data in dst is discarded.
+ */
+ public void copyTo(@NonNull SparseIntArray dst) {
+ dst.clear();
+ final int end = size();
+ for (int i = 0; i < end; i++) {
+ dst.put(keyAt(i), valueAt(i));
+ }
+ }
+
+ /**
+ * Return the underlying storage. This breaks the wrapper but is necessary when
+ * passing the array to distant methods.
+ */
+ public SparseIntArray untrackedStorage() {
+ return mStorage;
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or <code>false</code>
+ * if no such mapping has been made.
+ */
+ public int get(int key) {
+ return mStorage.get(key);
+ }
+
+ /**
+ * Gets the boolean mapped from the specified key, or the specified value
+ * if no such mapping has been made.
+ */
+ public int get(int key, int valueIfKeyNotFound) {
+ return mStorage.get(key, valueIfKeyNotFound);
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ // This code ensures that onChanged is called only if the key is actually
+ // present.
+ final int index = mStorage.indexOfKey(key);
+ if (index >= 0) {
+ mStorage.removeAt(index);
+ onChanged();
+ }
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index) {
+ mStorage.removeAt(index);
+ onChanged();
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, int value) {
+ // There is no fast way to know if the key exists with the input value, so this
+ // method always notifies change listeners.
+ mStorage.put(key, value);
+ onChanged();
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseIntArray
+ * currently stores.
+ */
+ public int size() {
+ return mStorage.size();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseIntArray stores.
+ *
+ * <p>The keys corresponding to indices in ascending order are guaranteed to
+ * be in ascending order, e.g., <code>keyAt(0)</code> will return the
+ * smallest key and <code>keyAt(size()-1)</code> will return the largest
+ * key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int keyAt(int index) {
+ return mStorage.keyAt(index);
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseIntArray stores.
+ *
+ * <p>The values corresponding to indices in ascending order are guaranteed
+ * to be associated with keys in ascending order, e.g.,
+ * <code>valueAt(0)</code> will return the value associated with the
+ * smallest key and <code>valueAt(size()-1)</code> will return the value
+ * associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public int valueAt(int index) {
+ return mStorage.valueAt(index);
+ }
+
+ /**
+ * Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ */
+ public void setValueAt(int index, int value) {
+ if (mStorage.valueAt(index) != value) {
+ mStorage.setValueAt(index, value);
+ onChanged();
+ }
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ return mStorage.indexOfKey(key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(int value) {
+ return mStorage.indexOfValue(value);
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseIntArray.
+ */
+ public void clear() {
+ final int count = size();
+ mStorage.clear();
+ if (count > 0) {
+ onChanged();
+ }
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, int value) {
+ mStorage.append(key, value);
+ onChanged();
+ }
+
+ /**
+ * Provides a copy of keys.
+ **/
+ public int[] copyKeys() {
+ return mStorage.copyKeys();
+ }
+
+ @Override
+ public int hashCode() {
+ return mStorage.hashCode();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof WatchedSparseIntArray) {
+ WatchedSparseIntArray w = (WatchedSparseIntArray) o;
+ return mStorage.equals(w.mStorage);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation composes a string by iterating over its mappings.
+ */
+ @Override
+ public String toString() {
+ return mStorage.toString();
+ }
+
+ /**
+ * Create a snapshot. The snapshot does not include any {@link Watchable}
+ * information.
+ */
+ public WatchedSparseIntArray snapshot() {
+ WatchedSparseIntArray l = new WatchedSparseIntArray(this);
+ l.seal();
+ return l;
+ }
+
+ /**
+ * Make <this> a snapshot of the argument. Note that <this> is immutable when the
+ * method returns. <this> must be empty when the function is called.
+ * @param r The source array, which is copied into <this>
+ */
+ public void snapshot(@NonNull WatchedSparseIntArray r) {
+ snapshot(this, r);
+ }
+
+ /**
+ * Make the destination a copy of the source. If the element is a subclass of Snapper then the
+ * copy contains snapshots of the elements. Otherwise the copy contains references to the
+ * elements. The destination must be initially empty. Upon return, the destination is
+ * immutable.
+ * @param dst The destination array. It must be empty.
+ * @param src The source array. It is not modified.
+ */
+ public static void snapshot(@NonNull WatchedSparseIntArray dst,
+ @NonNull WatchedSparseIntArray src) {
+ if (dst.size() != 0) {
+ throw new IllegalArgumentException("snapshot destination is not empty");
+ }
+ final int end = src.size();
+ for (int i = 0; i < end; i++) {
+ dst.put(src.keyAt(i), src.valueAt(i));
+ }
+ dst.seal();
+ }
+
+}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5289f8604f36..375c3e138a39 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1618,7 +1618,8 @@ class ActivityStarter {
mService.getTransitionController().collectExistenceChange(r);
}
if (newTransition != null) {
- mService.getTransitionController().requestStartTransition(newTransition);
+ mService.getTransitionController().requestStartTransition(newTransition,
+ r.getTask());
} else {
// Make the collecting transition wait until this request is ready.
mService.getTransitionController().setReady(false);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 61da564ebab0..9cbe2778359d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -744,7 +744,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mActivityClientController.onSystemReady();
mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, false);
+ BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, true);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 9d291b12c2c9..73a6efdb6799 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -2207,6 +2207,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
}
if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
+ if (mService.getTransitionController().getTransitionPlayer() != null) return;
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
final TaskDisplayArea taskDisplayArea = task.getDisplayArea();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index dde527d161e0..d562bde45925 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -154,7 +154,7 @@ public class AppTransitionController {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
// TODO(new-app-transition): Remove code using appTransition.getAppTransition()
final AppTransition appTransition = mDisplayContent.mAppTransition;
- mDisplayContent.mSkipAppTransitionAnimation = false;
+
mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
appTransition.removeAppTransitionTimeoutCallbacks();
@@ -188,7 +188,9 @@ public class AppTransitionController {
final @TransitionOldType int transit = getTransitCompatType(
mDisplayContent.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper());
+ mWallpaperControllerLocked.getWallpaperTarget(), getOldWallpaper(),
+ mDisplayContent.mSkipAppTransitionAnimation);
+ mDisplayContent.mSkipAppTransitionAnimation = false;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"handleAppTransitionReady: displayId=%d appTransition={%s}"
@@ -274,7 +276,8 @@ public class AppTransitionController {
*/
static @TransitionOldType int getTransitCompatType(AppTransition appTransition,
ArraySet<ActivityRecord> openingApps, ArraySet<ActivityRecord> closingApps,
- @Nullable WindowState wallpaperTarget, @Nullable WindowState oldWallpaper) {
+ @Nullable WindowState wallpaperTarget, @Nullable WindowState oldWallpaper,
+ boolean skipAppTransitionAnimation) {
// Determine if closing and opening app token sets are wallpaper targets, in which case
// special animations are needed.
@@ -298,6 +301,10 @@ public class AppTransitionController {
return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
}
+ // This is not keyguard transition and one of the app has request to skip app transition.
+ if (skipAppTransitionAnimation) {
+ return WindowManager.TRANSIT_OLD_UNSET;
+ }
final @TransitionFlags int flags = appTransition.getTransitFlags();
final @TransitionType int firstTransit = appTransition.getFirstAppTransition();
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index dc75bbeea452..6e8110e9c36e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1496,6 +1496,7 @@ class RecentTasks {
final Task removedTask = mTasks.remove(removeIndex);
if (removedTask != task) {
if (removedTask.hasChild()) {
+ Slog.i(TAG, "Add " + removedTask + " to hidden list because adding " + task);
// A non-empty task is replaced by a new task. Because the removed task is no longer
// managed by the recent tasks list, add it to the hidden list to prevent the task
// from becoming dangling.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a0e6b423f299..aa8865773795 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4421,8 +4421,17 @@ class Task extends WindowContainer<WindowContainer> {
sb.append(stringName);
sb.append(" U=");
sb.append(mUserId);
- sb.append(" StackId=");
- sb.append(getRootTaskId());
+ final Task rootTask = getRootTask();
+ if (rootTask != this) {
+ sb.append(" rootTaskId=");
+ sb.append(rootTask.mTaskId);
+ }
+ sb.append(" visible=");
+ sb.append(shouldBeVisible(null /* starting */));
+ sb.append(" mode=");
+ sb.append(windowingModeToString(getWindowingMode()));
+ sb.append(" translucent=");
+ sb.append(isTranslucent(null /* starting */));
sb.append(" sz=");
sb.append(getChildCount());
sb.append('}');
@@ -4432,10 +4441,7 @@ class Task extends WindowContainer<WindowContainer> {
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" #");
sb.append(mTaskId);
- sb.append(" visible=" + shouldBeVisible(null /* starting */));
sb.append(" type=" + activityTypeToString(getActivityType()));
- sb.append(" mode=" + windowingModeToString(getWindowingMode()));
- sb.append(" translucent=" + isTranslucent(null /* starting */));
if (affinity != null) {
sb.append(" A=");
sb.append(affinity);
@@ -5180,9 +5186,6 @@ class Task extends WindowContainer<WindowContainer> {
@Override
public void setWindowingMode(int windowingMode) {
- // Reset the cached result of toString()
- stringName = null;
-
// Calling Task#setWindowingMode() for leaf task since this is the a specialization of
// {@link #setWindowingMode(int)} for ActivityStack.
if (!isRootTask()) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index be78d7a18377..b37e3c42f568 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -37,6 +37,7 @@ import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -567,6 +568,10 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
tmpList.add(wc);
}
for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) {
+ if (!p.isAttached() || !changes.get(p).hasChanged(p)) {
+ // Again, we're skipping no-ops
+ break;
+ }
if (participants.contains(p)) {
topParent = p;
break;
@@ -695,6 +700,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
final TransitionInfo.Change change = new TransitionInfo.Change(
target.mRemoteToken != null ? target.mRemoteToken.toWindowContainerToken()
: null, target.getSurfaceControl());
+ // TODO(shell-transitions): Use leash for non-organized windows.
if (info.mParent != null) {
change.setParent(info.mParent.mRemoteToken.toWindowContainerToken());
}
@@ -704,6 +710,12 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
change.setEndRelOffset(target.getBounds().left - target.getParent().getBounds().left,
target.getBounds().top - target.getParent().getBounds().top);
change.setFlags(info.getChangeFlags(target));
+ final Task task = target.asTask();
+ if (task != null) {
+ final ActivityManager.RunningTaskInfo tinfo = new ActivityManager.RunningTaskInfo();
+ task.fillTaskInfo(tinfo);
+ change.setTaskInfo(tinfo);
+ }
out.addChange(change);
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 2f5d10afe3da..0fe0afa54dd3 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -21,6 +21,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -167,7 +168,8 @@ class TransitionController {
// Make the collecting transition wait until this request is ready.
mCollectingTransition.setReady(false);
} else {
- newTransition = requestStartTransition(createTransition(type, flags));
+ newTransition = requestStartTransition(createTransition(type, flags),
+ trigger != null ? trigger.asTask() : null);
}
if (trigger != null) {
if (isExistenceType(type)) {
@@ -181,11 +183,16 @@ class TransitionController {
/** Asks the transition player (shell) to start a created but not yet started transition. */
@NonNull
- Transition requestStartTransition(@NonNull Transition transition) {
+ Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask) {
try {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Requesting StartTransition: %s", transition);
- mTransitionPlayer.requestStartTransition(transition.mType, transition);
+ ActivityManager.RunningTaskInfo info = null;
+ if (startTask != null) {
+ info = new ActivityManager.RunningTaskInfo();
+ startTask.fillTaskInfo(info);
+ }
+ mTransitionPlayer.requestStartTransition(transition.mType, transition, info);
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting transition", e);
transition.start();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4eeae6c0710c..3bdc16f0107a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2332,15 +2332,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- // We may be deferring layout passes at the moment, but since the client is interested
- // in the new out values right now we need to force a layout.
- mWindowPlacerLocked.performSurfacePlacement(true /* force */);
-
+ // Create surfaceControl before surface placement otherwise layout will be skipped
+ // (because WS.isGoneForLayout() is true when there is no surface.
if (shouldRelayout) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
-
- result = win.relayoutVisibleWindow(result, attrChanges);
-
try {
result = createSurfaceControl(outSurfaceControl, result, win, winAnimator);
} catch (Exception e) {
@@ -2352,6 +2346,17 @@ public class WindowManagerService extends IWindowManager.Stub
Binder.restoreCallingIdentity(origId);
return 0;
}
+ }
+
+ // We may be deferring layout passes at the moment, but since the client is interested
+ // in the new out values right now we need to force a layout.
+ mWindowPlacerLocked.performSurfacePlacement(true /* force */);
+
+ if (shouldRelayout) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
+
+ result = win.relayoutVisibleWindow(result, attrChanges);
+
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
focusMayChange = true;
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 5f2b628e056a..b0e67ce17711 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -19,8 +19,8 @@ package com.android.server.wm;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
+import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -163,6 +163,11 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
try {
synchronized (mGlobalLock) {
Transition transition = Transition.fromBinder(transitionToken);
+ // In cases where transition is already provided, the "readiness lifecycle" of the
+ // transition is determined outside of this transaction. However, if this is a
+ // direct call from shell, the entire transition lifecycle is contained in the
+ // provided transaction and thus we can setReady immediately after apply.
+ boolean needsSetReady = transition == null && t != null;
if (transition == null) {
if (type < 0) {
throw new IllegalArgumentException("Can't create transition with no type");
@@ -174,6 +179,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
t = new WindowContainerTransaction();
}
applyTransaction(t, -1 /*syncId*/, transition);
+ if (needsSetReady) {
+ transition.setReady();
+ }
return transition;
}
} finally {
@@ -258,14 +266,21 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (transition != null) {
transition.collect(wc);
- if (hop.isReparent() && hop.getNewParent() != null) {
- final WindowContainer parentWc =
- WindowContainer.fromBinder(hop.getNewParent());
- if (parentWc == null) {
- Slog.e(TAG, "Can't resolve parent window from token");
- continue;
+ if (hop.isReparent()) {
+ if (wc.getParent() != null) {
+ // Collect the current parent. It's visibility may change as a result
+ // of this reparenting.
+ transition.collect(wc.getParent());
+ }
+ if (hop.getNewParent() != null) {
+ final WindowContainer parentWc =
+ WindowContainer.fromBinder(hop.getNewParent());
+ if (parentWc == null) {
+ Slog.e(TAG, "Can't resolve parent window from token");
+ continue;
+ }
+ transition.collect(parentWc);
}
- transition.collect(parentWc);
}
}
effects |= sanitizeAndApplyHierarchyOp(wc, hop);
@@ -307,6 +322,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
// Already calls ensureActivityConfig
mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+ mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
} else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
final PooledConsumer f = PooledLambda.obtainConsumer(
ActivityRecord::ensureActivityConfiguration,
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 88964b746aca..1cb9e5786a70 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -33,6 +33,7 @@
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
+ <xs:element type="highBrightnessMode" name="highBrightnessMode" minOccurs="0" maxOccurs="1"/>
<xs:element type="displayQuirks" name="quirks" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
@@ -46,6 +47,38 @@
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="highBrightnessMode">
+ <xs:all>
+ <xs:element name="transitionPoint" type="nonNegativeDecimal" minOccurs="1" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="minimumLux" type="nonNegativeDecimal" minOccurs="1" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/>
+ </xs:all>
+ <xs:attribute name="enabled" type="xs:boolean" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="hbmTiming">
+ <xs:all>
+ <xs:element name="timeWindowSecs" type="xs:nonNegativeInteger" minOccurs="1" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="timeMaxSecs" type="xs:nonNegativeInteger" minOccurs="1" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element name="timeMinSecs" type="xs:nonNegativeInteger" minOccurs="1" maxOccurs="1">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:all>
+ </xs:complexType>
+
<xs:complexType name="nitsMap">
<xs:sequence>
<xs:element name="point" type="point" maxOccurs="unbounded" minOccurs="2">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 6906fda5b76f..e073ab3675ca 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -3,9 +3,11 @@ package com.android.server.display.config {
public class DisplayConfiguration {
ctor public DisplayConfiguration();
+ method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
method public com.android.server.display.config.DisplayQuirks getQuirks();
method @NonNull public final java.math.BigDecimal getScreenBrightnessDefault();
method @NonNull public final com.android.server.display.config.NitsMap getScreenBrightnessMap();
+ method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
method public void setQuirks(com.android.server.display.config.DisplayQuirks);
method public final void setScreenBrightnessDefault(@NonNull java.math.BigDecimal);
method public final void setScreenBrightnessMap(@NonNull com.android.server.display.config.NitsMap);
@@ -16,6 +18,28 @@ package com.android.server.display.config {
method public java.util.List<java.lang.String> getQuirk();
}
+ public class HbmTiming {
+ ctor public HbmTiming();
+ method @NonNull public final java.math.BigInteger getTimeMaxSecs_all();
+ method @NonNull public final java.math.BigInteger getTimeMinSecs_all();
+ method @NonNull public final java.math.BigInteger getTimeWindowSecs_all();
+ method public final void setTimeMaxSecs_all(@NonNull java.math.BigInteger);
+ method public final void setTimeMinSecs_all(@NonNull java.math.BigInteger);
+ method public final void setTimeWindowSecs_all(@NonNull java.math.BigInteger);
+ }
+
+ public class HighBrightnessMode {
+ ctor public HighBrightnessMode();
+ method public boolean getEnabled();
+ method @NonNull public final java.math.BigDecimal getMinimumLux_all();
+ method public com.android.server.display.config.HbmTiming getTiming_all();
+ method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
+ method public void setEnabled(boolean);
+ method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
+ method public void setTiming_all(com.android.server.display.config.HbmTiming);
+ method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
+ }
+
public class NitsMap {
ctor public NitsMap();
method @NonNull public final java.util.List<com.android.server.display.config.Point> getPoint();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
index b6b4d8a04cb6..4e422b2374b2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/CallerIdentity.java
@@ -25,7 +25,7 @@ import android.os.UserHandle;
* All parameters are verified on object creation unless the component name is null and the
* caller is a delegate.
*/
-class CallerIdentity {
+final class CallerIdentity {
private final int mUid;
@Nullable
@@ -51,7 +51,7 @@ class CallerIdentity {
return UserHandle.getUserHandleForUid(mUid);
}
- @Nullable public String getPackageName() {
+ @Nullable public String getPackageName() {
return mPackageName;
}
@@ -66,4 +66,16 @@ class CallerIdentity {
public boolean hasPackage() {
return mPackageName != null;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("CallerIdentity[uid=").append(mUid);
+ if (mPackageName != null) {
+ builder.append(", pkg=").append(mPackageName);
+ }
+ if (mComponentName != null) {
+ builder.append(", cmp=").append(mComponentName.flattenToShortString());
+ }
+ return builder.append("]").toString();
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cd89f9ec12c2..fdbd85a77a5b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -983,8 +983,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
- Slog.i(LOG_TAG, "Setting DevicePolicySafetyChecker as " + safetyChecker);
+ CallerIdentity callerIdentity = getCallerIdentity();
+ Preconditions.checkCallAuthorization(mIsAutomotive || isAdb(callerIdentity), "can only set "
+ + "DevicePolicySafetyChecker on automotive builds or from ADB (but caller is %s)",
+ callerIdentity);
+ setDevicePolicySafetyCheckerUnchecked(safetyChecker);
+ }
+
+ /**
+ * Used by {@code setDevicePolicySafetyChecker()} above and {@link OneTimeSafetyChecker}.
+ */
+ void setDevicePolicySafetyCheckerUnchecked(DevicePolicySafetyChecker safetyChecker) {
+ Slog.i(LOG_TAG, String.format("Setting DevicePolicySafetyChecker as %s", safetyChecker));
mSafetyChecker = safetyChecker;
+ mInjector.setDevicePolicySafetyChecker(safetyChecker);
}
/**
@@ -1021,8 +1033,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public void setNextOperationSafety(@DevicePolicyOperation int operation, boolean safe) {
Preconditions.checkCallAuthorization(
hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
- Slog.i(LOG_TAG, "setNextOperationSafety(" + DevicePolicyManager.operationToString(operation)
- + ", " + safe + ")");
+ Slog.i(LOG_TAG, String.format("setNextOperationSafety(%s, %b)",
+ DevicePolicyManager.operationToString(operation), safe));
mSafetyChecker = new OneTimeSafetyChecker(this, operation, safe);
}
@@ -1034,6 +1046,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public final Context mContext;
+ private @Nullable DevicePolicySafetyChecker mSafetyChecker;
+
Injector(Context context) {
mContext = context;
}
@@ -1278,7 +1292,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
boolean wipeEuicc, boolean wipeExtRequested, boolean wipeResetProtectionData)
throws IOException {
- FactoryResetter.newBuilder(mContext).setReason(reason).setShutdown(shutdown)
+ FactoryResetter.newBuilder(mContext).setSafetyChecker(mSafetyChecker)
+ .setReason(reason).setShutdown(shutdown)
.setForce(force).setWipeEuicc(wipeEuicc)
.setWipeAdoptableStorage(wipeExtRequested)
.setWipeFactoryResetProtection(wipeResetProtectionData)
@@ -1433,6 +1448,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
public boolean isChangeEnabled(long changeId, String packageName, int userId) {
return CompatChanges.isChangeEnabled(changeId, packageName, UserHandle.of(userId));
}
+
+ void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
+ mSafetyChecker = safetyChecker;
+ }
}
/**
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
index a0cf7a31650d..564950bef4f5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/FactoryResetter.java
@@ -17,14 +17,18 @@
package com.android.server.devicepolicy;
import android.annotation.Nullable;
+import android.app.admin.DevicePolicySafetyChecker;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Bundle;
import android.os.RecoverySystem;
+import android.os.RemoteException;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.service.persistentdata.PersistentDataBlockManager;
-import android.util.Log;
+import android.util.Slog;
+import com.android.internal.os.IResultReceiver;
import com.android.internal.util.Preconditions;
import java.io.IOException;
@@ -38,6 +42,7 @@ public final class FactoryResetter {
private static final String TAG = FactoryResetter.class.getSimpleName();
private final Context mContext;
+ private final @Nullable DevicePolicySafetyChecker mSafetyChecker;
private final @Nullable String mReason;
private final boolean mShutdown;
private final boolean mForce;
@@ -45,18 +50,40 @@ public final class FactoryResetter {
private final boolean mWipeAdoptableStorage;
private final boolean mWipeFactoryResetProtection;
-
/**
* Factory reset the device according to the builder's arguments.
*/
public void factoryReset() throws IOException {
- Log.i(TAG, String.format("factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b"
- + ", wipeAdoptableStorage=%b, wipeFRP=%b", mReason, mShutdown, mForce, mWipeEuicc,
- mWipeAdoptableStorage, mWipeFactoryResetProtection));
-
Preconditions.checkCallAuthorization(mContext.checkCallingOrSelfPermission(
android.Manifest.permission.MASTER_CLEAR) == PackageManager.PERMISSION_GRANTED);
+ if (mSafetyChecker == null) {
+ factoryResetInternalUnchecked();
+ return;
+ }
+
+ IResultReceiver receiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ Slog.i(TAG, String.format("Factory reset confirmed by %s, proceeding",
+ mSafetyChecker));
+ try {
+ factoryResetInternalUnchecked();
+ } catch (IOException e) {
+ // Shouldn't happen
+ Slog.wtf(TAG, "IOException calling underlying systems", e);
+ }
+ }
+ };
+ Slog.i(TAG, String.format("Delaying factory reset until %s confirms", mSafetyChecker));
+ mSafetyChecker.onFactoryReset(receiver);
+ }
+
+ private void factoryResetInternalUnchecked() throws IOException {
+ Slog.i(TAG, String.format("factoryReset(): reason=%s, shutdown=%b, force=%b, wipeEuicc=%b, "
+ + "wipeAdoptableStorage=%b, wipeFRP=%b", mReason, mShutdown, mForce, mWipeEuicc,
+ mWipeAdoptableStorage, mWipeFactoryResetProtection));
+
UserManager um = mContext.getSystemService(UserManager.class);
if (!mForce && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Factory reset is not allowed for this user.");
@@ -66,15 +93,15 @@ public final class FactoryResetter {
PersistentDataBlockManager manager = mContext
.getSystemService(PersistentDataBlockManager.class);
if (manager != null) {
- Log.w(TAG, "Wiping factory reset protection");
+ Slog.w(TAG, "Wiping factory reset protection");
manager.wipe();
} else {
- Log.w(TAG, "No need to wipe factory reset protection");
+ Slog.w(TAG, "No need to wipe factory reset protection");
}
}
if (mWipeAdoptableStorage) {
- Log.w(TAG, "Wiping adoptable storage");
+ Slog.w(TAG, "Wiping adoptable storage");
StorageManager sm = mContext.getSystemService(StorageManager.class);
sm.wipeAdoptableDisks();
}
@@ -84,8 +111,9 @@ public final class FactoryResetter {
private FactoryResetter(Builder builder) {
mContext = builder.mContext;
- mShutdown = builder.mShutdown;
+ mSafetyChecker = builder.mSafetyChecker;
mReason = builder.mReason;
+ mShutdown = builder.mShutdown;
mForce = builder.mForce;
mWipeEuicc = builder.mWipeEuicc;
mWipeAdoptableStorage = builder.mWipeAdoptableStorage;
@@ -105,6 +133,7 @@ public final class FactoryResetter {
public static final class Builder {
private final Context mContext;
+ private @Nullable DevicePolicySafetyChecker mSafetyChecker;
private @Nullable String mReason;
private boolean mShutdown;
private boolean mForce;
@@ -117,6 +146,15 @@ public final class FactoryResetter {
}
/**
+ * Sets a {@link DevicePolicySafetyChecker} object that will be used to delay the
+ * factory reset when it's not safe to do so.
+ */
+ public Builder setSafetyChecker(@Nullable DevicePolicySafetyChecker safetyChecker) {
+ mSafetyChecker = safetyChecker;
+ return this;
+ }
+
+ /**
* Sets the (non-null) reason for the factory reset that is visible in the logs
*/
public Builder setReason(String reason) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
index b0f8bfb713ab..f7a826156d68 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OneTimeSafetyChecker.java
@@ -21,6 +21,8 @@ import android.app.admin.DevicePolicyManager.DevicePolicyOperation;
import android.app.admin.DevicePolicySafetyChecker;
import android.util.Slog;
+import com.android.internal.os.IResultReceiver;
+
import java.util.Objects;
//TODO(b/172376923): add unit tests
@@ -61,7 +63,12 @@ final class OneTimeSafetyChecker implements DevicePolicySafetyChecker {
}
Slog.i(TAG, "isDevicePolicyOperationSafe(" + name + "): returning " + safe
+ " and restoring DevicePolicySafetyChecker to " + mRealSafetyChecker);
- mService.setDevicePolicySafetyChecker(mRealSafetyChecker);
+ mService.setDevicePolicySafetyCheckerUnchecked(mRealSafetyChecker);
return safe;
}
+
+ @Override
+ public void onFactoryReset(IResultReceiver callback) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/services/musicrecognition/OWNERS b/services/musicrecognition/OWNERS
new file mode 100644
index 000000000000..58f5d40dd8c3
--- /dev/null
+++ b/services/musicrecognition/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 830636
+
+joannechung@google.com
+oni@google.com
+volnov@google.com
+
diff --git a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
index 829e3124dc39..c4d14f947cda 100644
--- a/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/devicepolicy/FactoryResetterTest.java
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.app.admin.DevicePolicySafetyChecker;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.RecoverySystem;
@@ -35,6 +36,8 @@ import android.platform.test.annotations.Presubmit;
import android.service.persistentdata.PersistentDataBlockManager;
import android.util.Log;
+import com.android.internal.os.IResultReceiver;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -58,6 +61,7 @@ public final class FactoryResetterTest {
private @Mock StorageManager mSm;
private @Mock PersistentDataBlockManager mPdbm;
private @Mock UserManager mUm;
+ private @Mock DevicePolicySafetyChecker mSafetyChecker;
@Before
public void startSession() {
@@ -69,7 +73,7 @@ public final class FactoryResetterTest {
when(mContext.getSystemService(any(Class.class))).thenAnswer((inv) -> {
Log.d(TAG, "Mocking " + inv);
- Class serviceClass = (Class) inv.getArguments()[0];
+ Class<?> serviceClass = (Class<?>) inv.getArguments()[0];
if (serviceClass.equals(PersistentDataBlockManager.class)) return mPdbm;
if (serviceClass.equals(StorageManager.class)) return mSm;
if (serviceClass.equals(UserManager.class)) return mUm;
@@ -194,6 +198,44 @@ public final class FactoryResetterTest {
verifyRebootWipeUserDataAllArgsCalled();
}
+ @Test
+ public void testFactoryReset_minimumArgs_safetyChecker_neverReplied() throws Exception {
+ allowFactoryReset();
+
+ FactoryResetter.newBuilder(mContext).setSafetyChecker(mSafetyChecker).build()
+ .factoryReset();
+
+ verifyWipeAdoptableStorageNotCalled();
+ verifyWipeFactoryResetProtectionNotCalled();
+ verifyRebootWipeUserDataNotCalled();
+ }
+
+ @Test
+ public void testFactoryReset_allArgs_safetyChecker_replied() throws Exception {
+ allowFactoryReset();
+
+ doAnswer((inv) -> {
+ Log.d(TAG, "Mocking " + inv);
+ IResultReceiver receiver = (IResultReceiver) inv.getArguments()[0];
+ receiver.send(0, null);
+ return null;
+ }).when(mSafetyChecker).onFactoryReset(any());
+
+ FactoryResetter.newBuilder(mContext)
+ .setSafetyChecker(mSafetyChecker)
+ .setReason(REASON)
+ .setForce(true)
+ .setShutdown(true)
+ .setWipeEuicc(true)
+ .setWipeAdoptableStorage(true)
+ .setWipeFactoryResetProtection(true)
+ .build().factoryReset();
+
+ verifyWipeAdoptableStorageCalled();
+ verifyWipeFactoryResetProtectionCalled();
+ verifyRebootWipeUserDataAllArgsCalled();
+ }
+
private void revokeMasterClearPermission() {
when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.MASTER_CLEAR))
.thenReturn(PackageManager.PERMISSION_DENIED);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 78bcc13c9265..4740df5a2a44 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -383,27 +383,6 @@ public class ConnectivityControllerTest {
}
@Test
- public void testWouldBeReadyWithConnectivityLocked() {
- final ConnectivityController controller = spy(new ConnectivityController(mService));
- final JobStatus red = createJobStatus(createJob()
- .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
- .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED);
-
- doReturn(false).when(controller).isNetworkAvailable(any());
- assertFalse(controller.wouldBeReadyWithConnectivityLocked(red));
-
- doReturn(true).when(controller).isNetworkAvailable(any());
- doReturn(false).when(controller).wouldBeReadyWithConstraintLocked(any(),
- eq(JobStatus.CONSTRAINT_CONNECTIVITY));
- assertFalse(controller.wouldBeReadyWithConnectivityLocked(red));
-
- doReturn(true).when(controller).isNetworkAvailable(any());
- doReturn(true).when(controller).wouldBeReadyWithConstraintLocked(any(),
- eq(JobStatus.CONSTRAINT_CONNECTIVITY));
- assertTrue(controller.wouldBeReadyWithConnectivityLocked(red));
- }
-
- @Test
public void testEvaluateStateLocked_JobWithoutConnectivity() {
final ConnectivityController controller = new ConnectivityController(mService);
final JobStatus red = createJobStatus(createJob().setMinimumLatency(1));
@@ -417,7 +396,9 @@ public class ConnectivityControllerTest {
@Test
public void testEvaluateStateLocked_JobWouldBeReady() {
final ConnectivityController controller = spy(new ConnectivityController(mService));
- doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any());
+ doReturn(true).when(controller)
+ .wouldBeReadyWithConstraintLocked(any(), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
+ doReturn(true).when(controller).isNetworkAvailable(any());
final JobStatus red = createJobStatus(createJob()
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED);
@@ -455,7 +436,8 @@ public class ConnectivityControllerTest {
@Test
public void testEvaluateStateLocked_JobWouldNotBeReady() {
final ConnectivityController controller = spy(new ConnectivityController(mService));
- doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any());
+ doReturn(false).when(controller)
+ .wouldBeReadyWithConstraintLocked(any(), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
final JobStatus red = createJobStatus(createJob()
.setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED), UID_RED);
@@ -523,21 +505,26 @@ public class ConnectivityControllerTest {
.setAppIdleWhitelist(eq(12345), anyBoolean());
// Both jobs would still be ready. Exception should not be revoked.
- doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(any());
+ doReturn(true).when(controller)
+ .wouldBeReadyWithConstraintLocked(any(), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
+ doReturn(true).when(controller).isNetworkAvailable(any());
controller.reevaluateStateLocked(UID_RED);
inOrder.verify(mNetPolicyManagerInternal, never())
.setAppIdleWhitelist(eq(UID_RED), anyBoolean());
// One job is still ready. Exception should not be revoked.
- doReturn(true).when(controller).wouldBeReadyWithConnectivityLocked(eq(redOne));
- doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(eq(redTwo));
+ doReturn(true).when(controller).wouldBeReadyWithConstraintLocked(
+ eq(redOne), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
+ doReturn(false).when(controller).wouldBeReadyWithConstraintLocked(
+ eq(redTwo), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
controller.reevaluateStateLocked(UID_RED);
inOrder.verify(mNetPolicyManagerInternal, never())
.setAppIdleWhitelist(eq(UID_RED), anyBoolean());
assertTrue(controller.isStandbyExceptionRequestedLocked(UID_RED));
// Both jobs are not ready. Exception should be revoked.
- doReturn(false).when(controller).wouldBeReadyWithConnectivityLocked(any());
+ doReturn(false).when(controller)
+ .wouldBeReadyWithConstraintLocked(any(), eq(JobStatus.CONSTRAINT_CONNECTIVITY));
controller.reevaluateStateLocked(UID_RED);
inOrder.verify(mNetPolicyManagerInternal, times(1))
.setAppIdleWhitelist(eq(UID_RED), eq(false));
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 05f1ed8a20b3..1a65894f85b1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -136,6 +136,8 @@ public class QuotaControllerTest {
@Mock
private JobSchedulerService mJobSchedulerService;
@Mock
+ private PackageManagerInternal mPackageManagerInternal;
+ @Mock
private UsageStatsManagerInternal mUsageStatsManager;
private JobStore mJobStore;
@@ -172,7 +174,7 @@ public class QuotaControllerTest {
doReturn(mUsageStatsManager)
.when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
// Used in JobStatus.
- doReturn(mock(PackageManagerInternal.class))
+ doReturn(mPackageManagerInternal)
.when(() -> LocalServices.getService(PackageManagerInternal.class));
// Used in QuotaController.Handler.
mJobStore = JobStore.initAndGetForTesting(mContext, mContext.getFilesDir());
@@ -2377,6 +2379,7 @@ public class QuotaControllerTest {
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 1 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 30 * MINUTE_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 27 * MINUTE_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 10 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 12 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 10 * MINUTE_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 87 * SECOND_IN_MILLIS);
@@ -2414,6 +2417,7 @@ public class QuotaControllerTest {
assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
assertEquals(30 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
assertEquals(27 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
+ assertEquals(10 * HOUR_IN_MILLIS, mQuotaController.getEjLimitSpecialAdditionMs());
assertEquals(12 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());
assertEquals(87 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
@@ -2452,6 +2456,7 @@ public class QuotaControllerTest {
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, -1);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, -1);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, -1);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, -1);
setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, -1);
setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, -1);
setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, -1);
@@ -2486,6 +2491,7 @@ public class QuotaControllerTest {
assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
assertEquals(10 * MINUTE_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
assertEquals(0, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
+ assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs());
assertEquals(HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
assertEquals(1, mQuotaController.getEJTopAppTimeChunkSizeMs());
assertEquals(10 * SECOND_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
@@ -2518,6 +2524,7 @@ public class QuotaControllerTest {
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_FREQUENT_MS, 25 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RARE_MS, 25 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_RESTRICTED_MS, 25 * HOUR_IN_MILLIS);
+ setDeviceConfigLong(QcConstants.KEY_EJ_LIMIT_SPECIAL_ADDITION_MS, 25 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_WINDOW_SIZE_MS, 25 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_TOP_APP_TIME_CHUNK_SIZE_MS, 25 * HOUR_IN_MILLIS);
setDeviceConfigLong(QcConstants.KEY_EJ_REWARD_TOP_APP_MS, 25 * HOUR_IN_MILLIS);
@@ -2542,6 +2549,7 @@ public class QuotaControllerTest {
assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[FREQUENT_INDEX]);
assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RARE_INDEX]);
assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitsMs()[RESTRICTED_INDEX]);
+ assertEquals(0, mQuotaController.getEjLimitSpecialAdditionMs());
assertEquals(24 * HOUR_IN_MILLIS, mQuotaController.getEJLimitWindowSizeMs());
assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJTopAppTimeChunkSizeMs());
assertEquals(15 * MINUTE_IN_MILLIS, mQuotaController.getEJRewardTopAppMs());
@@ -3498,6 +3506,37 @@ public class QuotaControllerTest {
}
@Test
+ public void testGetRemainingEJExecutionTimeLocked_SpecialApp() {
+ doReturn(new String[]{SOURCE_PACKAGE}).when(mPackageManagerInternal)
+ .getKnownPackageNames(eq(PackageManagerInternal.PACKAGE_VERIFIER), anyInt());
+ mQuotaController.onSystemServicesReady();
+
+ final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - mQcConstants.EJ_WINDOW_SIZE_MS, MINUTE_IN_MILLIS, 5),
+ true);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - 40 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - 30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - 20 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+ mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+ createTimingSession(now - 10 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 5), true);
+
+ final long[] limits = mQuotaController.getEJLimitsMs();
+ for (int i = 0; i < limits.length; ++i) {
+ setStandbyBucket(i);
+ assertEquals("Got wrong remaining EJ execution time for bucket #" + i,
+ i == NEVER_INDEX ? 0
+ : (limits[i] + mQuotaController.getEjLimitSpecialAdditionMs()
+ - 5 * MINUTE_IN_MILLIS),
+ mQuotaController.getRemainingEJExecutionTimeLocked(
+ SOURCE_USER_ID, SOURCE_PACKAGE));
+ }
+ }
+
+ @Test
public void testGetRemainingEJExecutionTimeLocked_OneSessionStraddlesEdge() {
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
final long[] limits = mQuotaController.getEJLimitsMs();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
index 9d847153661f..d64c1b31e343 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java
@@ -711,25 +711,31 @@ public class TimeControllerTest {
.set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());
// Test evaluating something before the current deadline.
+ doReturn(false).when(mTimeController)
+ .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
+ mTimeController.evaluateStateLocked(jobEarliest);
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(), eq(TAG_DELAY), any(), any(), any());
doReturn(true).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
mTimeController.evaluateStateLocked(jobEarliest);
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(), eq(TAG_DELAY),
any(), any(), any());
- // Job goes back to not being ready. Middle is still true, so use that alarm.
+ // Job goes back to not being ready. Middle is still true, but we don't check and actively
+ // defer alarm.
doReturn(false).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
mTimeController.evaluateStateLocked(jobEarliest);
- inOrder.verify(mAlarmManager, times(1))
- .set(anyInt(), eq(now + 30 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(),
eq(TAG_DELAY), any(), any(), any());
- // Turn middle off. Latest is true, so use that alarm.
+ // Turn middle off. Latest is true, but we don't check and actively defer alarm.
doReturn(false).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobMiddle), anyInt());
mTimeController.evaluateStateLocked(jobMiddle);
- inOrder.verify(mAlarmManager, times(1))
- .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(),
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(),
eq(TAG_DELAY), any(), any(), any());
}
@@ -768,25 +774,32 @@ public class TimeControllerTest {
.set(anyInt(), anyLong(), anyLong(), anyLong(), anyString(), any(), any(), any());
// Test evaluating something before the current deadline.
+ doReturn(false).when(mTimeController)
+ .wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
+ mTimeController.evaluateStateLocked(jobEarliest);
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(),
+ eq(TAG_DEADLINE), any(), any(), any());
doReturn(true).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
mTimeController.evaluateStateLocked(jobEarliest);
inOrder.verify(mAlarmManager, times(1))
.set(anyInt(), eq(now + 5 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
eq(TAG_DEADLINE), any(), any(), any());
- // Job goes back to not being ready. Middle is still true, so use that alarm.
+ // Job goes back to not being ready. Middle is still true, but we don't check and actively
+ // defer alarm.
doReturn(false).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobEarliest), anyInt());
mTimeController.evaluateStateLocked(jobEarliest);
- inOrder.verify(mAlarmManager, times(1))
- .set(anyInt(), eq(now + 30 * MINUTE_IN_MILLIS), anyLong(), anyLong(),
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(),
eq(TAG_DEADLINE), any(), any(), any());
- // Turn middle off. Latest is true, so use that alarm.
+ // Turn middle off. Latest is true, but we don't check and actively defer alarm.
doReturn(false).when(mTimeController)
.wouldBeReadyWithConstraintLocked(eq(jobMiddle), anyInt());
mTimeController.evaluateStateLocked(jobMiddle);
- inOrder.verify(mAlarmManager, times(1))
- .set(anyInt(), eq(now + HOUR_IN_MILLIS), anyLong(), anyLong(),
+ inOrder.verify(mAlarmManager, never())
+ .set(anyInt(), anyLong(), anyLong(), anyLong(),
eq(TAG_DEADLINE), any(), any(), any());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 24e7d7d19e8d..1fc075156349 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -218,7 +218,7 @@ public class BiometricSchedulerTest {
@NonNull LazyDaemon<Object> lazyDaemon, int cookie) {
super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */,
TAG, cookie, TEST_SENSOR_ID, 0 /* statsModality */,
- 0 /* statsAction */, 0 /* statsClient */);
+ 0 /* statsAction */, 0 /* statsClient */, true /* shouldLogMetrics */);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1c7da3b98930..c1b1133dbb22 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -116,7 +116,9 @@ import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.internal.util.collections.Sets;
@@ -206,6 +208,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
private static final String PROFILE_OFF_SUSPENSION_TEXT = "suspension_text";
private static final String PROFILE_OFF_SUSPENSION_SOON_TEXT = "suspension_tomorrow_text";
+ @BeforeClass
+ public static void setUpClass() {
+ Notification.DevFlags.sForceDefaults = true;
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ Notification.DevFlags.sForceDefaults = false;
+ }
+
@Before
public void setUp() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 1d2dcaecf978..6068fdf9b5b5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import android.annotation.Nullable;
import android.app.AppOpsManager;
@@ -33,6 +34,7 @@ import android.os.Handler;
import android.os.UserHandle;
import android.test.mock.MockContext;
import android.util.ArrayMap;
+import android.util.DisplayMetrics;
import android.util.ExceptionUtils;
import androidx.annotation.NonNull;
@@ -174,6 +176,11 @@ public class DpmMockContext extends MockContext {
binder = new MockBinder();
resources = mock(Resources.class);
spiedContext = mock(Context.class);
+
+ // Set up density for notification building
+ DisplayMetrics displayMetrics = mock(DisplayMetrics.class);
+ displayMetrics.density = 2.25f;
+ when(resources.getDisplayMetrics()).thenReturn(displayMetrics);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index ec747acd376d..23a4c2f417c5 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -53,21 +53,29 @@ public class AutomaticBrightnessControllerTest {
private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0;
private static final float DOZE_SCALE_FACTOR = 0.0f;
private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
+ private static final int DISPLAY_ID = 0;
+ private static final int LAYER_STACK = 0;
private Context mContext;
+ private LogicalDisplay mLogicalDisplay;
+
@Mock SensorManager mSensorManager;
@Mock BrightnessMappingStrategy mBrightnessMappingStrategy;
@Mock HysteresisLevels mAmbientBrightnessThresholds;
@Mock HysteresisLevels mScreenBrightnessThresholds;
- @Mock Handler mNoopHandler;
+ @Mock Handler mNoOpHandler;
@Mock DisplayDeviceConfig mDisplayDeviceConfig;
+ @Mock DisplayDevice mDisplayDevice;
private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
@Before
public void setUp() {
+ // Share classloader to allow package private access.
+ System.setProperty("dexmaker.share_classloader", "true");
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getContext();
+ mLogicalDisplay = new LogicalDisplay(DISPLAY_ID, LAYER_STACK, mDisplayDevice);
}
private AutomaticBrightnessController setupController(Sensor lightSensor) {
@@ -75,7 +83,7 @@ public class AutomaticBrightnessControllerTest {
new AutomaticBrightnessController.Injector() {
@Override
public Handler getBackgroundThreadHandler() {
- return mNoopHandler;
+ return mNoOpHandler;
}
},
() -> { }, mContext.getMainLooper(), mSensorManager, lightSensor,
@@ -83,7 +91,7 @@ public class AutomaticBrightnessControllerTest {
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
- mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mContext
+ mAmbientBrightnessThresholds, mScreenBrightnessThresholds, mLogicalDisplay, mContext
);
controller.setLoggingEnabled(true);
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
index 23365f70b2f4..5cff2081e59e 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/ControllerImplTest.java
@@ -28,6 +28,7 @@ import static com.android.server.location.timezone.TimeZoneProviderEvent.createU
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -923,6 +924,74 @@ public class ControllerImplTest {
assertFalse(controllerImpl.isUncertaintyTimeoutSet());
}
+ @Test
+ public void stateRecording() {
+ ControllerImpl controllerImpl = new ControllerImpl(mTestThreadingDomain,
+ mTestPrimaryLocationTimeZoneProvider, mTestSecondaryLocationTimeZoneProvider);
+ TestEnvironment testEnvironment = new TestEnvironment(
+ mTestThreadingDomain, controllerImpl, USER1_CONFIG_GEO_DETECTION_ENABLED);
+
+ // Initialize and check initial state.
+ controllerImpl.initialize(testEnvironment, mTestCallback);
+
+ {
+ LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
+ assertNull(state.getLastSuggestion());
+ assertTrue(state.getPrimaryProviderStates().isEmpty());
+ assertTrue(state.getSecondaryProviderStates().isEmpty());
+ }
+
+ // State recording and simulate some provider behavior that will show up in the state
+ // recording.
+ controllerImpl.setProviderStateRecordingEnabled(true);
+
+ // Simulate an uncertain event from the primary. This will start the secondary.
+ mTestPrimaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
+ USER1_UNCERTAIN_LOCATION_TIME_ZONE_EVENT);
+
+ {
+ LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
+ assertNull(state.getLastSuggestion());
+ List<LocationTimeZoneProvider.ProviderState> primaryProviderStates =
+ state.getPrimaryProviderStates();
+ assertEquals(1, primaryProviderStates.size());
+ assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN,
+ primaryProviderStates.get(0).stateEnum);
+ List<LocationTimeZoneProvider.ProviderState> secondaryProviderStates =
+ state.getSecondaryProviderStates();
+ assertEquals(1, secondaryProviderStates.size());
+ assertEquals(PROVIDER_STATE_STARTED_INITIALIZING,
+ secondaryProviderStates.get(0).stateEnum);
+ }
+
+ // Simulate an uncertain event from the primary. This will start the secondary.
+ mTestSecondaryLocationTimeZoneProvider.simulateTimeZoneProviderEvent(
+ USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1);
+
+ {
+ LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
+ assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
+ state.getLastSuggestion().getZoneIds());
+ List<LocationTimeZoneProvider.ProviderState> primaryProviderStates =
+ state.getPrimaryProviderStates();
+ assertEquals(1, primaryProviderStates.size());
+ assertEquals(PROVIDER_STATE_STARTED_UNCERTAIN, primaryProviderStates.get(0).stateEnum);
+ List<LocationTimeZoneProvider.ProviderState> secondaryProviderStates =
+ state.getSecondaryProviderStates();
+ assertEquals(2, secondaryProviderStates.size());
+ assertEquals(PROVIDER_STATE_STARTED_CERTAIN, secondaryProviderStates.get(1).stateEnum);
+ }
+
+ controllerImpl.setProviderStateRecordingEnabled(false);
+ {
+ LocationTimeZoneManagerServiceState state = controllerImpl.getStateForTests();
+ assertEquals(USER1_SUCCESS_LOCATION_TIME_ZONE_EVENT1.getSuggestion().getTimeZoneIds(),
+ state.getLastSuggestion().getZoneIds());
+ assertTrue(state.getPrimaryProviderStates().isEmpty());
+ assertTrue(state.getSecondaryProviderStates().isEmpty());
+ }
+ }
+
private static void assertUncertaintyTimeoutSet(
LocationTimeZoneProviderController.Environment environment,
LocationTimeZoneProviderController controller) {
diff --git a/services/tests/servicestests/src/com/android/server/location/timezone/LocationTimeZoneProviderTest.java b/services/tests/servicestests/src/com/android/server/location/timezone/LocationTimeZoneProviderTest.java
index 49c67ea1b8f1..cb292db50115 100644
--- a/services/tests/servicestests/src/com/android/server/location/timezone/LocationTimeZoneProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/timezone/LocationTimeZoneProviderTest.java
@@ -18,6 +18,7 @@ package com.android.server.location.timezone;
import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_ERROR_KEY;
import static android.service.timezone.TimeZoneProviderService.TEST_COMMAND_RESULT_SUCCESS_KEY;
+import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_DESTROYED;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_CERTAIN;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_INITIALIZING;
import static com.android.server.location.timezone.LocationTimeZoneProvider.ProviderState.PROVIDER_STATE_STARTED_UNCERTAIN;
@@ -49,6 +50,7 @@ import org.junit.Test;
import java.time.Duration;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -174,6 +176,48 @@ public class LocationTimeZoneProviderTest {
assertNotNull(result.getString(TEST_COMMAND_RESULT_ERROR_KEY));
}
+ @Test
+ public void stateRecording() {
+ String providerName = "primary";
+ TestLocationTimeZoneProvider provider =
+ new TestLocationTimeZoneProvider(mTestThreadingDomain, providerName);
+ provider.setStateChangeRecordingEnabled(true);
+
+ // initialize()
+ provider.initialize(mProviderListener);
+ provider.assertLatestRecordedState(PROVIDER_STATE_STOPPED);
+
+ // startUpdates()
+ ConfigurationInternal config = USER1_CONFIG_GEO_DETECTION_ENABLED;
+ Duration arbitraryInitializationTimeout = Duration.ofMinutes(5);
+ Duration arbitraryInitializationTimeoutFuzz = Duration.ofMinutes(2);
+ provider.startUpdates(config, arbitraryInitializationTimeout,
+ arbitraryInitializationTimeoutFuzz);
+ provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_INITIALIZING);
+
+ // Simulate a suggestion event being received.
+ TimeZoneProviderSuggestion suggestion = new TimeZoneProviderSuggestion.Builder()
+ .setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+ .setTimeZoneIds(Arrays.asList("Europe/London"))
+ .build();
+ TimeZoneProviderEvent event = TimeZoneProviderEvent.createSuggestionEvent(suggestion);
+ provider.simulateProviderEventReceived(event);
+ provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_CERTAIN);
+
+ // Simulate an uncertain event being received.
+ event = TimeZoneProviderEvent.createUncertainEvent();
+ provider.simulateProviderEventReceived(event);
+ provider.assertLatestRecordedState(PROVIDER_STATE_STARTED_UNCERTAIN);
+
+ // stopUpdates()
+ provider.stopUpdates();
+ provider.assertLatestRecordedState(PROVIDER_STATE_STOPPED);
+
+ // destroy()
+ provider.destroy();
+ provider.assertLatestRecordedState(PROVIDER_STATE_DESTROYED);
+ }
+
/** A test stand-in for the real {@link LocationTimeZoneProviderController}'s listener. */
private static class TestProviderListener implements ProviderListener {
@@ -257,5 +301,11 @@ public class LocationTimeZoneProviderTest {
void assertOnDestroyCalled() {
assertTrue(mOnDestroyCalled);
}
+
+ void assertLatestRecordedState(@ProviderState.ProviderStateEnum int expectedStateEnum) {
+ List<ProviderState> recordedStates = getRecordedStates();
+ assertEquals(expectedStateEnum,
+ recordedStates.get(recordedStates.size() - 1).stateEnum);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 205548cc8d3c..9a52643b57f2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -209,7 +209,10 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
verify(mFeatureConfigMock).onSystemReady();
}
@@ -218,45 +221,60 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter,
pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("add package");
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
+ watcher.verifyChangeReported("add package");
assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterAplication");
}
-
@Test
public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
final Signature frameworkSignature = Mockito.mock(Signature.class);
final PackageParser.SigningDetails frameworkSigningDetails =
new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
final ParsingPackage android = pkg("android");
+ watcher.verifyNoChangeReported("prepare");
android.addProtectedBroadcast("TEST_ACTION");
simulateAddPackage(appsFilter, android, 1000,
b -> b.setSigningDetails(frameworkSigningDetails));
+ watcher.verifyChangeReported("addPackage");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
final int activityUid = DUMMY_TARGET_APPID;
PackageSetting targetActivity = simulateAddPackage(appsFilter,
pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid);
+ watcher.verifyChangeReported("addPackage");
final int receiverUid = DUMMY_TARGET_APPID + 1;
PackageSetting targetReceiver = simulateAddPackage(appsFilter,
pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")),
receiverUid);
+ watcher.verifyChangeReported("addPackage");
final int callingUid = DUMMY_CALLING_APPID;
PackageSetting calling = simulateAddPackage(appsFilter,
pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid);
+ watcher.verifyChangeReported("addPackage");
final int wildcardUid = DUMMY_CALLING_APPID + 1;
PackageSetting callingWildCard = simulateAddPackage(appsFilter,
pkg("com.calling.wildcard", new Intent("*")), wildcardUid);
+ watcher.verifyChangeReported("addPackage");
assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity,
SYSTEM_USER));
@@ -267,6 +285,7 @@ public class AppsFilterTest {
wildcardUid, callingWildCard, targetActivity, SYSTEM_USER));
assertTrue(appsFilter.shouldFilterApplication(
wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -274,17 +293,24 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addPackage");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter,
pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("addPackage");
PackageSetting calling = simulateAddPackage(appsFilter,
pkgQueriesProvider("com.some.other.package", "com.some.authority"),
DUMMY_CALLING_APPID);
+ watcher.verifyChangeReported("addPackage");
assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -292,17 +318,24 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addPackage");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter,
pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("addPackage");
PackageSetting calling = simulateAddPackage(appsFilter,
pkgQueriesProvider("com.some.other.package", "com.some.other.authority"),
DUMMY_CALLING_APPID);
+ watcher.verifyChangeReported("addPackage");
assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterApplication");
}
@Test
@@ -779,16 +812,23 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("add package");
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, null, false));
+ watcher.verifyChangeReported("add package");
assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterAplication");
}
@Test
@@ -796,16 +836,23 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("add package");
PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, null, false));
+ watcher.verifyChangeReported("add package");
assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterAplication");
}
@Test
@@ -813,15 +860,20 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
appsFilter.onSystemReady();
-
+ watcher.verifyChangeReported("systemReady");
PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
DUMMY_TARGET_APPID);
+ watcher.verifyChangeReported("add package");
PackageSetting instrumentation = simulateAddPackage(appsFilter,
pkgWithInstrumentation("com.some.other.package", "com.some.package"),
DUMMY_CALLING_APPID);
+ watcher.verifyChangeReported("add package");
assertFalse(
appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
@@ -829,6 +881,7 @@ public class AppsFilterTest {
assertFalse(
appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
SYSTEM_USER));
+ watcher.verifyNoChangeReported("shouldFilterAplication");
}
@Test
@@ -836,8 +889,12 @@ public class AppsFilterTest {
final AppsFilter appsFilter =
new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
mMockExecutor);
+ final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+ watcher.register();
simulateAddBasicAndroid(appsFilter);
+ watcher.verifyChangeReported("addBasicAndroid");
appsFilter.onSystemReady();
+ watcher.verifyChangeReported("systemReady");
final int systemAppId = Process.FIRST_APPLICATION_UID - 1;
final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
@@ -845,25 +902,34 @@ public class AppsFilterTest {
final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
+ watcher.verifyChangeReported("add package");
PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
seesNothingAppId);
+ watcher.verifyChangeReported("add package");
PackageSetting hasProvider = simulateAddPackage(appsFilter,
pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId);
+ watcher.verifyChangeReported("add package");
PackageSetting queriesProvider = simulateAddPackage(appsFilter,
pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
queriesProviderAppId);
+ watcher.verifyChangeReported("add package");
final SparseArray<int[]> systemFilter =
appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
+ watcher.verifyNoChangeReported("getVisibility");
assertThat(toList(systemFilter.get(SYSTEM_USER)),
contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
+ watcher.verifyNoChangeReported("getVisibility");
final SparseArray<int[]> seesNothingFilter =
appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
+ watcher.verifyNoChangeReported("getVisibility");
assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
contains(seesNothingAppId));
+ watcher.verifyNoChangeReported("getVisibility");
assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
contains(seesNothingAppId));
+ watcher.verifyNoChangeReported("getVisibility");
final SparseArray<int[]> hasProviderFilter =
appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
@@ -872,17 +938,22 @@ public class AppsFilterTest {
SparseArray<int[]> queriesProviderFilter =
appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+ watcher.verifyNoChangeReported("getVisibility");
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
contains(queriesProviderAppId));
+ watcher.verifyNoChangeReported("getVisibility");
// provider read
appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ watcher.verifyChangeReported("grantImplicitAccess");
// ensure implicit access is included in the filter
queriesProviderFilter =
appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+ watcher.verifyNoChangeReported("getVisibility");
assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
contains(hasProviderAppId, queriesProviderAppId));
+ watcher.verifyNoChangeReported("getVisibility");
}
@Test
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 282047afaa51..333ec9295b93 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -1215,7 +1215,7 @@ public class PackageManagerSettingsTests {
private void verifyKeySetMetaData(Settings settings)
throws ReflectiveOperationException, IllegalAccessException {
ArrayMap<String, PackageSetting> packages =
- settings.mPackages.untrackedMap();
+ settings.mPackages.untrackedStorage();
KeySetManagerService ksms = settings.mKeySetManagerService;
/* verify keyset and public key ref counts */
diff --git a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 9bea9d4cedbd..7c65dc03a57e 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -20,12 +20,20 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
+
/**
* Test class for {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
* {@link WatchedArrayMap}, {@link WatchedSparseArray}, and
@@ -40,7 +48,7 @@ public class WatcherTest {
// A counter to generate unique IDs for Leaf elements.
private int mLeafId = 0;
- // Useful indices used int the tests.
+ // Useful indices used in the tests.
private static final int INDEX_A = 1;
private static final int INDEX_B = 2;
private static final int INDEX_C = 3;
@@ -171,6 +179,7 @@ public class WatcherTest {
@Test
public void testWatchedArrayMap() {
+ final String name = "WatchedArrayMap";
WatchableTester tester;
// Create a few leaves
@@ -183,7 +192,7 @@ public class WatcherTest {
WatchedArrayMap<Integer, Leaf> array = new WatchedArrayMap<>();
array.put(INDEX_A, leafA);
array.put(INDEX_B, leafB);
- tester = new WatchableTester(array, "WatchedArrayMap");
+ tester = new WatchableTester(array, name);
tester.verify(0, "Initial array - no registration");
leafA.tick();
tester.verify(0, "Updates with no registration");
@@ -231,20 +240,20 @@ public class WatcherTest {
final WatchedArrayMap<Integer, Leaf> arraySnap = array.snapshot();
tester.verify(14, "Generate snapshot (no changes)");
// Verify that the snapshot is a proper copy of the source.
- assertEquals("WatchedArrayMap snap same size",
+ assertEquals(name + " snap same size",
array.size(), arraySnap.size());
for (int i = 0; i < array.size(); i++) {
for (int j = 0; j < arraySnap.size(); j++) {
- assertTrue("WatchedArrayMap elements differ",
+ assertTrue(name + " elements differ",
array.valueAt(i) != arraySnap.valueAt(j));
}
- assertTrue("WatchedArrayMap element copy",
+ assertTrue(name + " element copy",
array.valueAt(i).equals(arraySnap.valueAt(i)));
}
leafD.tick();
tester.verify(15, "Tick after snapshot");
// Verify that the snapshot is sealed
- verifySealed("WatchedArrayMap", ()->arraySnap.put(INDEX_A, leafA));
+ verifySealed(name, ()->arraySnap.put(INDEX_A, leafA));
}
// Recreate the snapshot since the test corrupted it.
{
@@ -253,10 +262,235 @@ public class WatcherTest {
final Leaf arraySnapElement = arraySnap.valueAt(0);
verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
}
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out failed";
+ ArrayMap<Integer, Leaf> base = new ArrayMap<>();
+ array.copyTo(base);
+ WatchedArrayMap<Integer, Leaf> copy = new WatchedArrayMap<>();
+ copy.copyFrom(base);
+ if (!array.equals(copy)) {
+ fail(msg);
+ }
+ }
+ }
+
+ @Test
+ public void testWatchedArraySet() {
+ final String name = "WatchedArraySet";
+ WatchableTester tester;
+
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
+
+ // Test WatchedArraySet
+ WatchedArraySet<Leaf> array = new WatchedArraySet<>();
+ array.add(leafA);
+ array.add(leafB);
+ tester = new WatchableTester(array, name);
+ tester.verify(0, "Initial array - no registration");
+ leafA.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ leafA.tick();
+ tester.verify(1, "Updates with registration");
+ leafB.tick();
+ tester.verify(2, "Updates with registration");
+ array.remove(leafB);
+ tester.verify(3, "Removed b");
+ leafB.tick();
+ tester.verify(3, "Updates with b not watched");
+ array.add(leafB);
+ array.add(leafB);
+ tester.verify(5, "Added b once");
+ leafB.tick();
+ tester.verify(6, "Changed b - single notification");
+ array.remove(leafB);
+ tester.verify(7, "Removed b");
+ leafB.tick();
+ tester.verify(7, "Changed b - not watched");
+ array.remove(leafB);
+ tester.verify(7, "Removed non-existent b");
+ array.clear();
+ tester.verify(8, "Cleared array");
+ leafA.tick();
+ tester.verify(8, "Change to a not in array");
+
+ // Special methods
+ array.add(leafA);
+ array.add(leafB);
+ array.add(leafC);
+ tester.verify(11, "Added a, b, c");
+ leafC.tick();
+ tester.verify(12, "Ticked c");
+ array.removeAt(array.indexOf(leafC));
+ tester.verify(13, "Removed c");
+ leafC.tick();
+ tester.verify(13, "Ticked c, not registered");
+ array.append(leafC);
+ tester.verify(14, "Append c");
+ leafC.tick();
+ leafD.tick();
+ tester.verify(15, "Ticked d and c");
+ assertEquals("Verify three elements", 3, array.size());
+
+ // Snapshot
+ {
+ final WatchedArraySet<Leaf> arraySnap = array.snapshot();
+ tester.verify(15, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals(name + " snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue(name + " elements differ",
+ array.valueAt(i) != arraySnap.valueAt(j));
+ }
+ }
+ leafC.tick();
+ tester.verify(16, "Tick after snapshot");
+ // Verify that the array snapshot is sealed
+ verifySealed(name, ()->arraySnap.add(leafB));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedArraySet<Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.valueAt(0);
+ verifySealed(name + " snap element", ()->arraySnapElement.tick());
+ }
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out";
+ ArraySet<Leaf> base = new ArraySet<>();
+ array.copyTo(base);
+ WatchedArraySet<Leaf> copy = new WatchedArraySet<>();
+ copy.copyFrom(base);
+ if (!array.equals(copy)) {
+ fail(msg);
+ }
+ }
+ }
+
+ @Test
+ public void testWatchedArrayList() {
+ final String name = "WatchedArrayList";
+ WatchableTester tester;
+
+ // Create a few leaves
+ Leaf leafA = new Leaf();
+ Leaf leafB = new Leaf();
+ Leaf leafC = new Leaf();
+ Leaf leafD = new Leaf();
+
+ // Redefine the indices used in the tests to be zero-based
+ final int indexA = 0;
+ final int indexB = 1;
+ final int indexC = 2;
+ final int indexD = 3;
+
+ // Test WatchedArrayList
+ WatchedArrayList<Leaf> array = new WatchedArrayList<>();
+ // A spacer that takes up index 0 (and is not Watchable).
+ array.add(indexA, leafA);
+ array.add(indexB, leafB);
+ tester = new WatchableTester(array, name);
+ tester.verify(0, "Initial array - no registration");
+ leafA.tick();
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ leafA.tick();
+ tester.verify(1, "Updates with registration");
+ leafB.tick();
+ tester.verify(2, "Updates with registration");
+ array.remove(indexB);
+ tester.verify(3, "Removed b");
+ leafB.tick();
+ tester.verify(3, "Updates with b not watched");
+ array.add(indexB, leafB);
+ array.add(indexC, leafB);
+ tester.verify(5, "Added b twice");
+ leafB.tick();
+ tester.verify(6, "Changed b - single notification");
+ array.remove(indexC);
+ tester.verify(7, "Removed first b");
+ leafB.tick();
+ tester.verify(8, "Changed b - single notification");
+ array.remove(indexB);
+ tester.verify(9, "Removed second b");
+ leafB.tick();
+ tester.verify(9, "Updated leafB - no change");
+ array.clear();
+ tester.verify(10, "Cleared array");
+ leafB.tick();
+ tester.verify(10, "Change to b not in array");
+
+ // Special methods
+ array.add(indexA, leafA);
+ array.add(indexB, leafB);
+ array.add(indexC, leafC);
+ tester.verify(13, "Added c");
+ leafC.tick();
+ tester.verify(14, "Ticked c");
+ array.set(array.indexOf(leafC), leafD);
+ tester.verify(15, "Replaced c with d");
+ leafC.tick();
+ leafD.tick();
+ tester.verify(16, "Ticked d and c (c not registered)");
+ array.add(leafC);
+ tester.verify(17, "Append c");
+ leafC.tick();
+ leafD.tick();
+ tester.verify(19, "Ticked d and c");
+
+ // Snapshot
+ {
+ final WatchedArrayList<Leaf> arraySnap = array.snapshot();
+ tester.verify(19, "Generate snapshot (no changes)");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals(name + " snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ for (int j = 0; j < arraySnap.size(); j++) {
+ assertTrue(name + " elements differ",
+ array.get(i) != arraySnap.get(j));
+ }
+ assertTrue(name + " element copy",
+ array.get(i).equals(arraySnap.get(i)));
+ }
+ leafD.tick();
+ tester.verify(20, "Tick after snapshot");
+ // Verify that the array snapshot is sealed
+ verifySealed(name, ()->arraySnap.add(indexA, leafB));
+ }
+ // Recreate the snapshot since the test corrupted it.
+ {
+ final WatchedArrayList<Leaf> arraySnap = array.snapshot();
+ // Verify that elements are also snapshots
+ final Leaf arraySnapElement = arraySnap.get(0);
+ verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
+ }
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out";
+ ArrayList<Leaf> base = new ArrayList<>();
+ array.copyTo(base);
+ WatchedArrayList<Leaf> copy = new WatchedArrayList<>();
+ copy.copyFrom(base);
+ if (!array.equals(copy)) {
+ fail(msg);
+ }
+ }
}
@Test
public void testWatchedSparseArray() {
+ final String name = "WatchedSparseArray";
WatchableTester tester;
// Create a few leaves
@@ -269,7 +503,7 @@ public class WatcherTest {
WatchedSparseArray<Leaf> array = new WatchedSparseArray<>();
array.put(INDEX_A, leafA);
array.put(INDEX_B, leafB);
- tester = new WatchableTester(array, "WatchedSparseArray");
+ tester = new WatchableTester(array, name);
tester.verify(0, "Initial array - no registration");
leafA.tick();
tester.verify(0, "Updates with no registration");
@@ -338,20 +572,20 @@ public class WatcherTest {
final WatchedSparseArray<Leaf> arraySnap = array.snapshot();
tester.verify(22, "Generate snapshot (no changes)");
// Verify that the snapshot is a proper copy of the source.
- assertEquals("WatchedSparseArray snap same size",
+ assertEquals(name + " snap same size",
array.size(), arraySnap.size());
for (int i = 0; i < array.size(); i++) {
for (int j = 0; j < arraySnap.size(); j++) {
- assertTrue("WatchedSparseArray elements differ",
+ assertTrue(name + " elements differ",
array.valueAt(i) != arraySnap.valueAt(j));
}
- assertTrue("WatchedArrayMap element copy",
+ assertTrue(name + " element copy",
array.valueAt(i).equals(arraySnap.valueAt(i)));
}
leafD.tick();
tester.verify(23, "Tick after snapshot");
// Verify that the array snapshot is sealed
- verifySealed("WatchedSparseArray", ()->arraySnap.put(INDEX_A, leafB));
+ verifySealed(name, ()->arraySnap.put(INDEX_A, leafB));
}
// Recreate the snapshot since the test corrupted it.
{
@@ -360,15 +594,30 @@ public class WatcherTest {
final Leaf arraySnapElement = arraySnap.valueAt(0);
verifySealed("ArraySnapshotElement", ()->arraySnapElement.tick());
}
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out";
+ SparseArray<Leaf> base = new SparseArray<>();
+ array.copyTo(base);
+ WatchedSparseArray<Leaf> copy = new WatchedSparseArray<>();
+ copy.copyFrom(base);
+ final int end = array.size();
+ assertTrue(msg + " size mismatch " + end + " " + copy.size(), end == copy.size());
+ for (int i = 0; i < end; i++) {
+ final int key = array.keyAt(i);
+ assertTrue(msg, array.get(i) == copy.get(i));
+ }
+ }
}
@Test
public void testWatchedSparseBooleanArray() {
+ final String name = "WatchedSparseBooleanArray";
WatchableTester tester;
// Test WatchedSparseBooleanArray
WatchedSparseBooleanArray array = new WatchedSparseBooleanArray();
- tester = new WatchableTester(array, "WatchedSparseBooleanArray");
+ tester = new WatchableTester(array, name);
tester.verify(0, "Initial array - no registration");
array.put(INDEX_A, true);
tester.verify(0, "Updates with no registration");
@@ -376,14 +625,10 @@ public class WatcherTest {
tester.verify(0, "Updates with no registration");
array.put(INDEX_B, true);
tester.verify(1, "Updates with registration");
- array.put(INDEX_B, true);
- tester.verify(1, "Null update");
array.put(INDEX_B, false);
array.put(INDEX_C, true);
tester.verify(3, "Updates with registration");
// Special methods
- array.put(INDEX_C, true);
- tester.verify(3, "Added true, no change");
array.setValueAt(array.indexOfKey(INDEX_C), false);
tester.verify(4, "Replaced true with false");
array.append(INDEX_D, true);
@@ -403,7 +648,77 @@ public class WatcherTest {
array.put(INDEX_D, false);
tester.verify(6, "Tick after snapshot");
// Verify that the array is sealed
- verifySealed("WatchedSparseBooleanArray", ()->arraySnap.put(INDEX_D, false));
+ verifySealed(name, ()->arraySnap.put(INDEX_D, false));
+ }
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out";
+ SparseBooleanArray base = new SparseBooleanArray();
+ array.copyTo(base);
+ WatchedSparseBooleanArray copy = new WatchedSparseBooleanArray();
+ copy.copyFrom(base);
+ final int end = array.size();
+ assertTrue(msg + " size mismatch/2 " + end + " " + copy.size(), end == copy.size());
+ for (int i = 0; i < end; i++) {
+ final int key = array.keyAt(i);
+ assertTrue(msg + " element", array.get(i) == copy.get(i));
+ }
+ }
+ }
+
+ @Test
+ public void testWatchedSparseIntArray() {
+ final String name = "WatchedSparseIntArray";
+ WatchableTester tester;
+
+ // Test WatchedSparseIntArray
+ WatchedSparseIntArray array = new WatchedSparseIntArray();
+ tester = new WatchableTester(array, name);
+ tester.verify(0, "Initial array - no registration");
+ array.put(INDEX_A, 1);
+ tester.verify(0, "Updates with no registration");
+ tester.register();
+ tester.verify(0, "Updates with no registration");
+ array.put(INDEX_B, 2);
+ tester.verify(1, "Updates with registration");
+ array.put(INDEX_B, 4);
+ array.put(INDEX_C, 5);
+ tester.verify(3, "Updates with registration");
+ // Special methods
+ array.setValueAt(array.indexOfKey(INDEX_C), 7);
+ tester.verify(4, "Replaced 6 with 7");
+ array.append(INDEX_D, 8);
+ tester.verify(5, "Append 8");
+
+ // Snapshot
+ {
+ WatchedSparseIntArray arraySnap = array.snapshot();
+ tester.verify(5, "Generate snapshot");
+ // Verify that the snapshot is a proper copy of the source.
+ assertEquals("WatchedSparseIntArray snap same size",
+ array.size(), arraySnap.size());
+ for (int i = 0; i < array.size(); i++) {
+ assertEquals(name + " element copy",
+ array.valueAt(i), arraySnap.valueAt(i));
+ }
+ array.put(INDEX_D, 9);
+ tester.verify(6, "Tick after snapshot");
+ // Verify that the array is sealed
+ verifySealed(name, ()->arraySnap.put(INDEX_D, 10));
+ }
+ // Verify copy-in/out
+ {
+ final String msg = name + " copy-in/out";
+ SparseIntArray base = new SparseIntArray();
+ array.copyTo(base);
+ WatchedSparseIntArray copy = new WatchedSparseIntArray();
+ copy.copyFrom(base);
+ final int end = array.size();
+ assertTrue(msg + " size mismatch " + end + " " + copy.size(), end == copy.size());
+ for (int i = 0; i < end; i++) {
+ final int key = array.keyAt(i);
+ assertTrue(msg, array.get(i) == copy.get(i));
+ }
}
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
index a093e0d4a740..afcf08ef1562 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -80,7 +80,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
@Test
public void testReadExtraTag() throws Exception {
- String xml = "<requested_listeners>"
+ String xml = "<req_listeners>"
+ "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">"
+ "<allowed types=\"7\" />"
+ "<disallowed pkgs=\"\" />"
@@ -89,13 +89,13 @@ public class NotificationListenersTest extends UiServiceTestCase {
+ "<allowed types=\"4\" />"
+ "<disallowed pkgs=\"something\" />"
+ "</listener>"
- + "</requested_listeners>";
+ + "</req_listeners>";
TypedXmlPullParser parser = Xml.newFastPullParser();
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(xml.getBytes())), null);
parser.nextTag();
- mListeners.readExtraTag("requested_listeners", parser);
+ mListeners.readExtraTag("req_listeners", parser);
validateListenersFromXml();
}
@@ -120,7 +120,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
parser.setInput(new BufferedInputStream(
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
- mListeners.readExtraTag("requested_listeners", parser);
+ mListeners.readExtraTag("req_listeners", parser);
validateListenersFromXml();
}
@@ -192,7 +192,7 @@ public class NotificationListenersTest extends UiServiceTestCase {
assertThat(mListeners.getNotificationListenerFilter(
Pair.create(si.getComponentName(), 0)).getTypes())
- .isEqualTo(7);
+ .isEqualTo(15);
assertThat(mListeners.getNotificationListenerFilter(Pair.create(si.getComponentName(), 0))
.getDisallowedPackages())
.isEmpty();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 6c824d6c87dc..ce5fc4021eac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -83,7 +83,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN,
AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null, null));
+ null, null, false));
}
@Test
@@ -99,7 +99,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
assertEquals(WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null, null));
+ null, null, false));
}
@Test
@@ -117,7 +117,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
assertEquals(TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null, null));
+ null, null, false));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 8cc515e83342..f1e36098d84e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -23,6 +23,7 @@ import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.TRANSIT_OPEN;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -81,7 +82,8 @@ public class AppTransitionTests extends WindowTestsBase {
assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
AppTransitionController.getTransitCompatType(mDc.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null /* wallpaperTarget */, null /* oldWallpaper */));
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /*skipAppTransitionAnimation*/));
}
@Test
@@ -95,7 +97,8 @@ public class AppTransitionTests extends WindowTestsBase {
assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
AppTransitionController.getTransitCompatType(mDc.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null /* wallpaperTarget */, null /* oldWallpaper */));
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /*skipAppTransitionAnimation*/));
}
@Test
@@ -109,7 +112,8 @@ public class AppTransitionTests extends WindowTestsBase {
assertEquals(TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE,
AppTransitionController.getTransitCompatType(mDc.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null /* wallpaperTarget */, null /* oldWallpaper */));
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /*skipAppTransitionAnimation*/));
}
@Test
@@ -123,7 +127,23 @@ public class AppTransitionTests extends WindowTestsBase {
assertEquals(TRANSIT_OLD_KEYGUARD_GOING_AWAY,
AppTransitionController.getTransitCompatType(mDc.mAppTransition,
mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
- null /* wallpaperTarget */, null /* oldWallpaper */));
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /*skipAppTransitionAnimation*/));
+ }
+
+ @Test
+ public void testSkipTransitionAnimation() {
+ final DisplayContent dc = createNewDisplay(Display.STATE_ON);
+ final ActivityRecord activity = createActivityRecord(dc);
+
+ mDc.prepareAppTransition(TRANSIT_OPEN);
+ mDc.prepareAppTransition(TRANSIT_CLOSE);
+ mDc.mClosingApps.add(activity);
+ assertEquals(TRANSIT_OLD_UNSET,
+ AppTransitionController.getTransitCompatType(mDc.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ true /*skipAppTransitionAnimation*/));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 74248a950a38..401ace03c554 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -77,6 +77,7 @@ public class TransitionTests extends WindowTestsBase {
changes.put(oldTask, new Transition.ChangeInfo(true /* vis */, true /* exChg */));
changes.put(opening, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(true /* vis */, true /* exChg */));
+ fillChangeMap(changes, newTask);
// End states.
closing.mVisibleRequested = false;
opening.mVisibleRequested = true;
@@ -141,6 +142,7 @@ public class TransitionTests extends WindowTestsBase {
changes.put(opening, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
changes.put(opening2, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
changes.put(closing, new Transition.ChangeInfo(true /* vis */, true /* exChg */));
+ fillChangeMap(changes, newTask);
// End states.
closing.mVisibleRequested = false;
opening.mVisibleRequested = true;
@@ -189,6 +191,8 @@ public class TransitionTests extends WindowTestsBase {
changes.put(tda, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
changes.put(showing, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
changes.put(showing2, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+ fillChangeMap(changes, tda);
+
// End states.
showing.mVisibleRequested = true;
showing2.mVisibleRequested = true;
@@ -338,4 +342,12 @@ public class TransitionTests extends WindowTestsBase {
assertEquals(FLAG_SHOW_WALLPAPER, info.getChange(
tasks[showWallpaperTask].mRemoteToken.toWindowContainerToken()).getFlags());
}
+
+ /** Fill the change map with all the parents of top. Change maps are usually fully populated */
+ private static void fillChangeMap(ArrayMap<WindowContainer, Transition.ChangeInfo> changes,
+ WindowContainer top) {
+ for (WindowContainer curr = top.getParent(); curr != null; curr = curr.getParent()) {
+ changes.put(curr, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+ }
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index d587f1e383c5..6bf2c855f08a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -19,8 +19,21 @@ package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
import androidx.test.uiautomator.UiDevice
-class ImeAppAutoFocusHelper(instr: Instrumentation) : ImeAppHelper(instr, "ImeAppAutoFocus") {
+class ImeAppAutoFocusHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ private val rotation: Int,
+ private val imePackageName: String = IME_PACKAGE
+) : ImeAppHelper(instr, "ImeAppAutoFocus") {
override fun openIME(device: UiDevice) {
// do nothing (the app is focused automatically)
}
+
+ override fun open() {
+ val expectedPackage = if (rotation.isRotated()) {
+ imePackageName
+ } else {
+ packageName
+ }
+ launcherStrategy.launch(appName, expectedPackage)
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index b341e621d9ed..412a3c383785 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -61,10 +61,11 @@ class CloseImeAutoOpenWindowToAppTest(
@JvmStatic
fun getParams(): List<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppAutoFocusHelper(instrumentation)
return FlickerTestRunnerFactory(instrumentation)
.buildTest { configuration ->
+ val testApp = ImeAppAutoFocusHelper(instrumentation,
+ configuration.startRotation)
withTag { buildTestTag("imeToAppAutoOpen", testApp, configuration) }
repeat { configuration.repetitions }
setup {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 51a4ca86681b..60a798fda5e4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -61,10 +61,11 @@ class CloseImeAutoOpenWindowToHomeTest(
@JvmStatic
fun getParams(): List<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppAutoFocusHelper(instrumentation)
return FlickerTestRunnerFactory(instrumentation)
.buildTest { configuration ->
+ val testApp = ImeAppAutoFocusHelper(instrumentation,
+ configuration.startRotation)
withTestName {
buildTestTag("imeToHomeAutoOpen", testApp, configuration)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index c7114da50117..d1842739171d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -66,11 +66,12 @@ class ReOpenImeWindowTest(
@JvmStatic
fun getParams(): List<Array<Any>> {
val instrumentation = InstrumentationRegistry.getInstrumentation()
- val testApp = ImeAppAutoFocusHelper(instrumentation)
val testAppComponentName = ActivityOptions.IME_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME
return FlickerTestRunnerFactory(instrumentation, repetitions = 5)
.buildTest { configuration ->
+ val testApp = ImeAppAutoFocusHelper(instrumentation,
+ configuration.startRotation)
withTestName { buildTestTag("reOpenImeAutoFocus", testApp, configuration) }
repeat { configuration.repetitions }
setup {
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index b47be97ed002..cd4cfcf18804 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -20,6 +20,7 @@ import static com.android.server.connectivity.NetworkNotificationManager.Notific
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -39,6 +40,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import android.util.DisplayMetrics;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -46,7 +48,9 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
+import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.AdditionalAnswers;
@@ -82,6 +86,7 @@ public class NetworkNotificationManagerTest {
@Mock Context mCtx;
@Mock Resources mResources;
+ @Mock DisplayMetrics mDisplayMetrics;
@Mock PackageManager mPm;
@Mock TelephonyManager mTelephonyManager;
@Mock NotificationManager mNotificationManager;
@@ -93,6 +98,17 @@ public class NetworkNotificationManagerTest {
NetworkNotificationManager mManager;
+
+ @BeforeClass
+ public static void setUpClass() {
+ Notification.DevFlags.sForceDefaults = true;
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ Notification.DevFlags.sForceDefaults = false;
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -103,6 +119,7 @@ public class NetworkNotificationManagerTest {
mCellNai.networkInfo = mNetworkInfo;
mVpnNai.networkCapabilities = VPN_CAPABILITIES;
mVpnNai.networkInfo = mNetworkInfo;
+ mDisplayMetrics.density = 2.275f;
doReturn(true).when(mVpnNai).isVPN();
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
@@ -114,6 +131,7 @@ public class NetworkNotificationManagerTest {
.thenReturn(mNotificationManager);
when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
+ when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
@@ -136,15 +154,15 @@ public class NetworkNotificationManagerTest {
public void testTitleOfPrivateDnsBroken() {
// Test the title of mobile data.
verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of wifi.
verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
// Test the title of other networks.
verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
- reset(mResources);
+ clearInvocations(mResources);
}
@Test
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 89146f945e1f..435c3c0af817 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -64,7 +64,6 @@ import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
@@ -124,7 +123,7 @@ public class NetworkStatsCollectionTest {
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
+ collection.write(bos);
// clear structure completely
collection.reset();
@@ -152,7 +151,7 @@ public class NetworkStatsCollectionTest {
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
+ collection.write(bos);
// clear structure completely
collection.reset();
@@ -180,7 +179,7 @@ public class NetworkStatsCollectionTest {
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- collection.write(new DataOutputStream(bos));
+ collection.write(bos);
// clear structure completely
collection.reset();