summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp6
-rw-r--r--Android.mk4
-rw-r--r--StubLibraries.bp28
-rw-r--r--apex/Android.bp3
-rw-r--r--apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java11
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java8
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java12
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java5
-rw-r--r--apex/statsd/aidl/Android.bp1
-rw-r--r--apex/statsd/framework/test/Android.bp11
-rw-r--r--api/current.txt1
-rw-r--r--api/module-lib-current.txt98
-rwxr-xr-xapi/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/statsd/Android.bp9
-rw-r--r--cmds/statsd/src/atoms.proto9
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp14
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h2
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp43
-rw-r--r--config/boot-image-profile.txt4
-rw-r--r--config/preloaded-classes4
-rw-r--r--core/java/android/annotation/SystemApi.java2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java4
-rw-r--r--core/java/android/app/AppOpsManager.java13
-rw-r--r--core/java/android/app/ApplicationPackageManager.java14
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java120
-rw-r--r--core/java/android/bluetooth/BluetoothMapClient.java69
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageManager.java13
-rw-r--r--core/java/android/content/res/Configuration.java14
-rw-r--r--core/java/android/hardware/Camera.java84
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java113
-rw-r--r--core/java/android/hardware/camera2/legacy/BurstHolder.java90
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceState.java362
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java805
-rw-r--r--core/java/android/hardware/camera2/legacy/CaptureCollector.java673
-rw-r--r--core/java/android/hardware/camera2/legacy/GLThreadManager.java264
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java886
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java138
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java265
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java321
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java1532
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequest.java67
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java688
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyResultMapper.java529
-rw-r--r--core/java/android/hardware/camera2/legacy/ParameterUtils.java1099
-rw-r--r--core/java/android/hardware/camera2/legacy/PerfMeasurement.java308
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestHandlerThread.java113
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestHolder.java283
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestQueue.java174
-rw-r--r--core/java/android/hardware/camera2/legacy/RequestThreadManager.java1126
-rw-r--r--core/java/android/hardware/camera2/legacy/SizeAreaComparator.java72
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java882
-rw-r--r--core/java/android/hardware/camera2/legacy/package.html3
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java5
-rw-r--r--core/java/android/hardware/camera2/utils/SurfaceUtils.java105
-rw-r--r--core/java/android/hardware/face/FaceManager.java96
-rw-r--r--core/java/android/hardware/face/FaceSensorProperties.aidl18
-rw-r--r--core/java/android/hardware/face/FaceSensorProperties.java70
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl11
-rw-r--r--core/java/android/hardware/face/IFaceServiceReceiver.aidl1
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java165
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl12
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl1
-rw-r--r--core/java/android/net/NetworkTemplate.java12
-rw-r--r--core/java/android/net/ProxyInfo.java12
-rw-r--r--core/java/android/os/DropBoxManager.java3
-rw-r--r--core/java/android/permission/PermissionControllerManager.java18
-rwxr-xr-xcore/java/android/provider/Settings.java7
-rw-r--r--core/java/android/provider/Telephony.java12
-rw-r--r--core/java/android/view/InsetsAnimationControlImpl.java2
-rw-r--r--core/java/android/view/InsetsController.java10
-rw-r--r--core/java/android/view/InsetsState.java19
-rw-r--r--core/java/android/view/View.java91
-rw-r--r--core/java/android/view/ViewGroup.java11
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/WindowInsets.java25
-rw-r--r--core/java/android/view/WindowManager.java137
-rw-r--r--core/java/android/view/WindowManagerImpl.java2
-rw-r--r--core/java/android/view/WindowManagerPolicyConstants.java7
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureSession.java3
-rw-r--r--core/java/android/widget/CompoundButton.java8
-rw-r--r--core/java/android/widget/ProgressBar.java15
-rw-r--r--core/java/android/widget/Switch.java6
-rw-r--r--core/java/android/widget/TextView.java5
-rw-r--r--core/java/android/widget/ToggleButton.java6
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java2
-rw-r--r--core/java/com/android/internal/net/VpnProfile.java3
-rw-r--r--core/java/com/android/internal/os/IDropBoxManagerService.aidl6
-rw-r--r--core/java/com/android/internal/os/KernelWakelockReader.java29
-rw-r--r--core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl51
-rw-r--r--core/jni/Android.bp3
-rw-r--r--core/jni/AndroidRuntime.cpp6
-rw-r--r--core/jni/android_hardware_Camera.cpp19
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp841
-rw-r--r--core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp335
-rw-r--r--core/jni/android_hardware_camera2_utils_SurfaceUtils.cpp229
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp27
-rw-r--r--core/jni/android_view_MotionEvent.cpp18
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp33
-rw-r--r--core/proto/android/providers/settings/secure.proto9
-rw-r--r--core/proto/android/server/windowmanagerservice.proto15
-rw-r--r--core/proto/android/typedef.proto30
-rw-r--r--core/proto/android/view/windowlayoutparams.proto25
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values-af/strings.xml4
-rw-r--r--core/res/res/values-ar/strings.xml4
-rw-r--r--core/res/res/values-as/strings.xml4
-rw-r--r--core/res/res/values-az/strings.xml4
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml4
-rw-r--r--core/res/res/values-be/strings.xml4
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-bn/strings.xml6
-rw-r--r--core/res/res/values-bs/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml4
-rw-r--r--core/res/res/values-cs/strings.xml4
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml20
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rAU/strings.xml4
-rw-r--r--core/res/res/values-en-rCA/strings.xml4
-rw-r--r--core/res/res/values-en-rGB/strings.xml4
-rw-r--r--core/res/res/values-en-rIN/strings.xml4
-rw-r--r--core/res/res/values-en-rXC/strings.xml4
-rw-r--r--core/res/res/values-es-rUS/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml4
-rw-r--r--core/res/res/values-et/strings.xml4
-rw-r--r--core/res/res/values-eu/strings.xml6
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr-rCA/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml4
-rw-r--r--core/res/res/values-gl/strings.xml4
-rw-r--r--core/res/res/values-gu/strings.xml6
-rw-r--r--core/res/res/values-hi/strings.xml4
-rw-r--r--core/res/res/values-hr/strings.xml4
-rw-r--r--core/res/res/values-hu/strings.xml4
-rw-r--r--core/res/res/values-hy/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml4
-rw-r--r--core/res/res/values-is/strings.xml4
-rw-r--r--core/res/res/values-it/strings.xml4
-rw-r--r--core/res/res/values-iw/strings.xml4
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ka/strings.xml4
-rw-r--r--core/res/res/values-kk/strings.xml4
-rw-r--r--core/res/res/values-km/strings.xml4
-rw-r--r--core/res/res/values-kn/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml4
-rw-r--r--core/res/res/values-ky/strings.xml4
-rw-r--r--core/res/res/values-lo/strings.xml4
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-lv/strings.xml4
-rw-r--r--core/res/res/values-mk/strings.xml4
-rw-r--r--core/res/res/values-ml/strings.xml6
-rw-r--r--core/res/res/values-mn/strings.xml4
-rw-r--r--core/res/res/values-mr/strings.xml4
-rw-r--r--core/res/res/values-ms/strings.xml4
-rw-r--r--core/res/res/values-my/strings.xml4
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-ne/strings.xml6
-rw-r--r--core/res/res/values-nl/strings.xml4
-rw-r--r--core/res/res/values-or/strings.xml6
-rw-r--r--core/res/res/values-pa/strings.xml4
-rw-r--r--core/res/res/values-pl/strings.xml4
-rw-r--r--core/res/res/values-pt-rBR/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-si/strings.xml4
-rw-r--r--core/res/res/values-sk/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml4
-rw-r--r--core/res/res/values-sq/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml4
-rw-r--r--core/res/res/values-sw/strings.xml4
-rw-r--r--core/res/res/values-ta/strings.xml4
-rw-r--r--core/res/res/values-te/strings.xml6
-rw-r--r--core/res/res/values-television/config.xml9
-rw-r--r--core/res/res/values-th/strings.xml4
-rw-r--r--core/res/res/values-tl/strings.xml4
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml4
-rw-r--r--core/res/res/values-ur/strings.xml4
-rw-r--r--core/res/res/values-uz/strings.xml4
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml4
-rw-r--r--core/res/res/values-zh-rHK/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values-zu/strings.xml4
-rw-r--r--core/tests/bluetoothtests/AndroidManifest.xml6
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java24
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java11
-rw-r--r--core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java156
-rw-r--r--core/tests/coretests/src/android/graphics/PaintNativeInstanceTest.kt161
-rw-r--r--core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java23
-rw-r--r--core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsControllerTest.java2
-rw-r--r--core/tests/coretests/src/android/view/InsetsStateTest.java36
-rw-r--r--data/etc/preinstalled-packages-platform-overlays.xml224
-rw-r--r--data/etc/privapp-permissions-platform.xml7
-rw-r--r--data/keyboards/OWNERS1
-rw-r--r--data/keyboards/Vendor_056e_Product_2010.kl48
-rw-r--r--data/keyboards/Vendor_056e_Product_2013.kl44
-rw-r--r--data/keyboards/Vendor_1532_Product_0709.kl51
-rw-r--r--data/keyboards/Vendor_27f8_Product_0bbf.kl54
-rw-r--r--graphics/java/android/graphics/ColorFilter.java4
-rw-r--r--graphics/java/android/graphics/ComposeShader.java10
-rw-r--r--graphics/java/android/graphics/Paint.java7
-rw-r--r--graphics/java/android/graphics/Shader.java21
-rw-r--r--libs/WindowManager/Shell/Android.bp4
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml (renamed from packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml)3
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml (renamed from packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml)3
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml (renamed from packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml)3
-rw-r--r--libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml (renamed from packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml)3
-rw-r--r--libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml20
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_expand.xml (renamed from packages/SystemUI/res/drawable/floating_dismiss_gradient.xml)22
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml (renamed from packages/SystemUI/res/drawable/pip_expand.xml)20
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml (renamed from packages/SystemUI/res/drawable/ic_pause_white.xml)5
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml (renamed from packages/SystemUI/res/drawable/ic_play_arrow_white.xml)5
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml28
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_icon.xml (renamed from packages/SystemUI/res/drawable/pip_icon.xml)4
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml (renamed from packages/SystemUI/res/drawable/pip_resize_handle.xml)4
-rw-r--r--libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml18
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu_action.xml23
-rw-r--r--libs/WindowManager/Shell/res/layout/pip_menu_activity.xml (renamed from packages/SystemUI/res/layout/pip_menu_activity.xml)25
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml (renamed from packages/SystemUI/res/layout/tv_pip_control_button.xml)29
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_controls.xml (renamed from packages/SystemUI/res/layout/tv_pip_controls.xml)35
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml21
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml31
-rw-r--r--libs/WindowManager/Shell/res/values-tvdpi/dimen.xml22
-rw-r--r--libs/WindowManager/Shell/res/values/config.xml42
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml58
-rw-r--r--libs/WindowManager/Shell/res/values/ids.xml19
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml56
-rw-r--r--libs/WindowManager/Shell/res/values/strings_tv.xml34
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp3
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp16
-rw-r--r--libs/hwui/jni/FontFamily.cpp12
-rw-r--r--libs/hwui/jni/fonts/Font.cpp12
-rw-r--r--location/java/android/location/package.html2
-rw-r--r--location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java30
-rw-r--r--media/java/android/media/MediaCas.java9
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java28
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java53
-rw-r--r--media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java47
-rw-r--r--non-updatable-api/current.txt1
-rw-r--r--non-updatable-api/module-lib-current.txt8
-rw-r--r--non-updatable-api/system-current.txt1
-rw-r--r--packages/CarSystemUI/TEST_MAPPING10
-rw-r--r--packages/CarSystemUI/res/layout/system_icons.xml6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java32
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java22
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java4
-rw-r--r--packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java2
-rw-r--r--packages/PackageInstaller/Android.bp1
-rw-r--r--packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java151
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java7
-rw-r--r--packages/Shell/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/Android.bp3
-rw-r--r--packages/SystemUI/proguard.flags4
-rw-r--r--packages/SystemUI/res/layout/pip_menu_action.xml22
-rw-r--r--packages/SystemUI/res/layout/qs_footer_impl.xml2
-rw-r--r--packages/SystemUI/res/layout/tv_pip_custom_control.xml23
-rw-r--r--packages/SystemUI/res/layout/tv_pip_menu.xml34
-rw-r--r--packages/SystemUI/res/values-af/strings.xml19
-rw-r--r--packages/SystemUI/res/values-am/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml19
-rw-r--r--packages/SystemUI/res/values-as/strings.xml19
-rw-r--r--packages/SystemUI/res/values-az/strings.xml19
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml19
-rw-r--r--packages/SystemUI/res/values-be/strings.xml19
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml19
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml23
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml19
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml19
-rw-r--r--packages/SystemUI/res/values-da/strings.xml19
-rw-r--r--packages/SystemUI/res/values-de/strings.xml23
-rw-r--r--packages/SystemUI/res/values-el/strings.xml19
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml19
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml19
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml19
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml19
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml19
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml19
-rw-r--r--packages/SystemUI/res/values-es/strings.xml19
-rw-r--r--packages/SystemUI/res/values-et/strings.xml19
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml19
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml29
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml19
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml19
-rw-r--r--packages/SystemUI/res/values-in/strings.xml19
-rw-r--r--packages/SystemUI/res/values-is/strings.xml19
-rw-r--r--packages/SystemUI/res/values-it/strings.xml19
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml19
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml19
-rw-r--r--packages/SystemUI/res/values-km/strings.xml23
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml19
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml19
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml19
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml19
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml23
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml19
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml23
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml19
-rw-r--r--packages/SystemUI/res/values-my/strings.xml19
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml23
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-or/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml23
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml19
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml19
-rw-r--r--packages/SystemUI/res/values-si/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml19
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml19
-rw-r--r--packages/SystemUI/res/values-te/strings.xml23
-rw-r--r--packages/SystemUI/res/values-th/strings.xml19
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml19
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml19
-rw-r--r--packages/SystemUI/res/values-tvdpi/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml19
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml23
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml19
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml19
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml19
-rw-r--r--packages/SystemUI/res/values/config.xml12
-rw-r--r--packages/SystemUI/res/values/config_tv.xml9
-rw-r--r--packages/SystemUI/res/values/dimens.xml40
-rw-r--r--packages/SystemUI/res/values/ids.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml60
-rw-r--r--packages/SystemUI/res/values/strings_tv.xml15
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/LogLevel.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java24
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java91
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt48
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java40
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java131
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java30
-rw-r--r--packages/Tethering/common/TetheringLib/api/module-lib-current.txt88
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java3
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java1
-rw-r--r--packages/Tethering/tests/privileged/Android.bp30
-rw-r--r--packages/Tethering/tests/privileged/AndroidManifest.xml32
-rw-r--r--packages/WAPPushManager/AndroidManifest.xml2
-rw-r--r--packages/services/PacProcessor/src/com/android/net/IProxyService.aidl3
-rw-r--r--packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java10
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java24
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java12
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java3
-rw-r--r--services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java16
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java95
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java16
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java18
-rw-r--r--services/backup/java/com/android/server/backup/internal/BackupHandler.java16
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java30
-rw-r--r--services/backup/java/com/android/server/backup/params/AdbBackupParams.java7
-rw-r--r--services/backup/java/com/android/server/backup/params/BackupParams.java8
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java10
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java (renamed from services/backup/java/com/android/server/backup/utils/AppBackupUtils.java)97
-rw-r--r--services/backup/java/com/android/server/backup/utils/RestoreUtils.java4
-rw-r--r--services/backup/java/com/android/server/backup/utils/TarBackupReader.java5
-rw-r--r--services/core/java/com/android/server/DropBoxManagerService.java22
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java31
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java25
-rw-r--r--services/core/java/com/android/server/TEST_MAPPING15
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java37
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java2
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java12
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java27
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/AuthService.java25
-rw-r--r--services/core/java/com/android/server/biometrics/Utils.java49
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java22
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java50
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationConsumer.java29
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java45
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java681
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java9
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/EnrollClient.java23
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/LockoutResetDispatcher.java (renamed from services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java)4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java28
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/Face10.java657
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java13
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceService.java725
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java94
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java117
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java30
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java123
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java33
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java110
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityDispatcher.java (renamed from services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java)4
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java24
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java82
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java56
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java13
-rw-r--r--services/core/java/com/android/server/connectivity/ProxyTracker.java2
-rw-r--r--services/core/java/com/android/server/media/MediaResourceMonitorService.java18
-rw-r--r--services/core/java/com/android/server/net/IpConfigStore.java3
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java37
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java15
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java125
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java128
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java56
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java6
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java14
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java5
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java879
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java63
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java238
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java23
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java3
-rw-r--r--services/incremental/IncrementalService.cpp15
-rw-r--r--services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java16
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java68
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowBackupEligibilityRules.java (renamed from services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java)17
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java4
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java52
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java (renamed from services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java)162
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java122
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java28
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java67
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java8
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java3
-rw-r--r--startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java13
-rw-r--r--telephony/api/system-current.txt1
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java4
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.java5
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java11
-rw-r--r--telephony/java/android/telephony/DataSpecificRegistrationInfo.java48
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java44
-rw-r--r--telephony/java/android/telephony/ServiceState.java25
-rw-r--r--telephony/java/android/telephony/SmsManager.java4
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java86
-rw-r--r--telephony/java/android/telephony/ims/feature/MmTelFeature.java19
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java34
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java86
-rw-r--r--tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java16
-rw-r--r--tests/FlickerTests/AndroidManifest.xml2
-rw-r--r--tests/FlickerTests/AndroidTest.xml2
-rw-r--r--tests/FlickerTests/README.md190
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt4
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt2
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml4
-rw-r--r--tests/RollbackTest/Android.bp3
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java37
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java33
-rw-r--r--tests/benchmarks/internal/Android.bp26
-rw-r--r--tests/benchmarks/internal/AndroidManifest.xml (renamed from packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml)17
-rw-r--r--tests/benchmarks/internal/AndroidTest.xml (renamed from packages/SystemUI/res/drawable/tv_pip_button_focused.xml)16
-rw-r--r--tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java454
-rw-r--r--tests/net/java/android/net/NetworkTemplateTest.kt7
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java55
-rw-r--r--tools/processors/intdef_mappings/Android.bp33
-rw-r--r--tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt190
-rw-r--r--tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt162
-rw-r--r--tools/stats_log_api_gen/Android.bp20
-rw-r--r--tools/stats_log_api_gen/native_writer.cpp190
-rw-r--r--tools/stats_log_api_gen/utils.cpp4
-rw-r--r--tools/stats_log_api_gen/utils.h2
-rw-r--r--tools/validatekeymaps/Android.bp1
-rw-r--r--wifi/TEST_MAPPING12
589 files changed, 9242 insertions, 18255 deletions
diff --git a/Android.bp b/Android.bp
index aae78a02e32e..e19fe640d32b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -568,6 +568,7 @@ java_library {
"libcore-platform-compat-config",
"services-platform-compat-config",
"documents-ui-compat-config",
+ "calendar-provider-compat-config",
],
libs: ["framework-updatable-stubs-module_libs_api"],
static_libs: [
@@ -626,6 +627,9 @@ java_library {
// Additional dependencies needed to build the ike API classes.
"ike-internals",
],
+ plugins: [
+ "intdef-annotation-processor",
+ ],
libs: ["icing-java-proto-lite"],
apex_available: ["//apex_available:platform"],
visibility: [
@@ -886,6 +890,7 @@ java_library {
exclude_srcs: [
"core/proto/android/privacy.proto",
"core/proto/android/section.proto",
+ "core/proto/android/typedef.proto",
],
sdk_version: "9",
srcs: [
@@ -911,6 +916,7 @@ java_library {
exclude_srcs: [
"core/proto/android/privacy.proto",
"core/proto/android/section.proto",
+ "core/proto/android/typedef.proto",
],
sdk_version: "core_current",
// Protos have lots of MissingOverride and similar.
diff --git a/Android.mk b/Android.mk
index d8532489a786..46529eb64657 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,10 +32,6 @@ ifneq ($(ANDROID_BUILD_EMBEDDED),true)
# ============================================================
include $(CLEAR_VARS)
-# This is used by ide.mk as the list of source files that are
-# always included.
-INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
-
# sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
# So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
# $(OUT_DOCS)/offline-sdk.
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 56c568832ea9..2bd5aee0cd24 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -155,6 +155,9 @@ priv_apps = " " +
module_libs = " " +
" --show-annotation android.annotation.SystemApi\\(" +
"client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+ "\\)" +
+ " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\) "
droidstubs {
@@ -232,16 +235,10 @@ droidstubs {
}
/////////////////////////////////////////////////////////////////////
-// Following droidstubs modules are for extra APIs for modules.
-// The framework currently have two more API surfaces for modules:
-// @SystemApi(client=MODULE_APPS) and @SystemApi(client=MODULE_LIBRARIES)
+// Following droidstubs modules are for extra APIs for modules,
+// namely @SystemApi(client=MODULE_LIBRARIES) APIs.
/////////////////////////////////////////////////////////////////////
-// TODO(b/146727827) remove the *-api module when we can teach metalava
-// about the relationship among the API surfaces. Currently, these modules are only to generate
-// the API signature files and ensure that the APIs evolve in a backwards compatible manner.
-// They however are NOT used for building the API stub.
-
droidstubs {
name: "module-lib-api",
defaults: ["metalava-full-api-stubs-default"],
@@ -278,7 +275,7 @@ droidstubs {
name: "module-lib-api-stubs-docs-non-updatable",
defaults: ["metalava-non-updatable-api-stubs-default"],
arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args + module_libs,
+ args: metalava_framework_docs_args + priv_apps + module_libs,
check_api: {
current: {
api_file: "non-updatable-api/module-lib-current.txt",
@@ -291,17 +288,6 @@ droidstubs {
},
}
-// The following droidstub module generates source files for the API stub library for
-// modules. Note that it not only includes its own APIs but also other APIs that have
-// narrower scope (all @SystemApis, not just the ones with 'client=MODULE_LIBRARIES').
-
-droidstubs {
- name: "module-lib-api-stubs-docs",
- defaults: ["metalava-non-updatable-api-stubs-default"],
- arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args + priv_apps + module_libs,
-}
-
/////////////////////////////////////////////////////////////////////
// android_*_stubs_current modules are the stubs libraries compiled
// from *-api-stubs-docs
@@ -397,7 +383,7 @@ java_library_static {
java_library_static {
name: "android_module_lib_stubs_current",
- srcs: [ ":module-lib-api-stubs-docs" ],
+ srcs: [ ":module-lib-api-stubs-docs-non-updatable" ],
defaults: ["android_defaults_stubs_current"],
libs: ["sdk_system_29_android"],
}
diff --git a/apex/Android.bp b/apex/Android.bp
index 6d4dc8517237..410e21141f86 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -53,6 +53,9 @@ priv_apps = " " +
module_libs = " " +
" --show-annotation android.annotation.SystemApi\\(" +
"client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+ "\\)" +
+ " --show-for-stub-purposes-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
"\\) "
mainline_service_stubs_args =
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index 0b760a621d22..9850b5d254d8 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -61,6 +61,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
import com.android.server.blob.BlobStoreManagerService.DumpArgs;
@@ -496,14 +497,8 @@ class BlobMetadata {
final byte[] leaseesBytes = proto.getBytes();
// Construct the StatsEvent to represent this Blob
- return StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mBlobId)
- .writeLong(getSize())
- .writeLong(mBlobHandle.getExpiryTimeMillis())
- .writeByteArray(committersBytes)
- .writeByteArray(leaseesBytes)
- .build();
+ return FrameworkStatsLog.buildStatsEvent(atomTag, mBlobId, getSize(),
+ mBlobHandle.getExpiryTimeMillis(), committersBytes, leaseesBytes);
}
}
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index 2a4081ae16f8..398ccb69fbe8 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -7,7 +7,6 @@ import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManager.StandbyBuckets;
import android.app.usage.UsageStatsManager.SystemForcedReasons;
import android.content.Context;
-import android.os.Looper;
import android.util.IndentingPrintWriter;
import java.io.PrintWriter;
@@ -21,13 +20,12 @@ public interface AppStandbyInternal {
* TODO AppStandbyController should probably be a binder service, and then we shouldn't need
* this method.
*/
- static AppStandbyInternal newAppStandbyController(ClassLoader loader, Context context,
- Looper looper) {
+ static AppStandbyInternal newAppStandbyController(ClassLoader loader, Context context) {
try {
final Class<?> clazz = Class.forName("com.android.server.usage.AppStandbyController",
true, loader);
- final Constructor<?> ctor = clazz.getConstructor(Context.class, Looper.class);
- return (AppStandbyInternal) ctor.newInstance(context, looper);
+ final Constructor<?> ctor = clazz.getConstructor(Context.class);
+ return (AppStandbyInternal) ctor.newInstance(context);
} catch (NoSuchMethodException | InstantiationException
| IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {
throw new RuntimeException("Unable to instantiate AppStandbyController!", e);
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 68b22c002d78..a67e928c8cbe 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2287,7 +2287,8 @@ public class JobSchedulerService extends com.android.server.SystemService
}
// Everything else checked out so far, so this is the final yes/no check
- final boolean appIsBad = mActivityManagerInternal.isAppBad(service.applicationInfo);
+ final boolean appIsBad = mActivityManagerInternal.isAppBad(
+ service.processName, service.applicationInfo.uid);
if (DEBUG && appIsBad) {
Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable");
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index f2a55805d70a..7bd51b77a119 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -335,7 +335,7 @@ public final class JobStore {
Slog.v(TAG, "Scheduling persist of jobs to disk.");
}
mIoHandler.postDelayed(mWriteRunnable, JOB_PERSIST_DELAY);
- mWriteScheduled = mWriteInProgress = true;
+ mWriteScheduled = true;
}
}
}
@@ -353,7 +353,7 @@ public final class JobStore {
throw new IllegalStateException("An asynchronous write is already scheduled.");
}
- mWriteScheduled = mWriteInProgress = true;
+ mWriteScheduled = true;
mWriteRunnable.run();
}
}
@@ -369,7 +369,7 @@ public final class JobStore {
final long start = SystemClock.uptimeMillis();
final long end = start + maxWaitMillis;
synchronized (mWriteScheduleLock) {
- while (mWriteInProgress) {
+ while (mWriteScheduled || mWriteInProgress) {
final long now = SystemClock.uptimeMillis();
if (now >= end) {
// still not done and we've hit the end; failure
@@ -404,6 +404,12 @@ public final class JobStore {
// a bit of lock contention.
synchronized (mWriteScheduleLock) {
mWriteScheduled = false;
+ if (mWriteInProgress) {
+ // Another runnable is currently writing. Postpone this new write task.
+ maybeWriteStatusToDiskAsync();
+ return;
+ }
+ mWriteInProgress = true;
}
synchronized (mLock) {
// Clone the jobs so we can release the lock before writing.
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 5059e09796f8..24436ea5180b 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -110,6 +110,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ConcurrentUtils;
+import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.usage.AppIdleHistory.AppUsageHistory;
@@ -418,8 +419,8 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
- public AppStandbyController(Context context, Looper looper) {
- this(new Injector(context, looper));
+ public AppStandbyController(Context context) {
+ this(new Injector(context, JobSchedulerBackgroundThread.get().getLooper()));
}
AppStandbyController(Injector injector) {
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 04339e67d799..f66cf7c9e23c 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -30,6 +30,7 @@ aidl_interface {
"android/os/StatsDimensionsValueParcel.aidl",
"android/util/StatsEventParcel.aidl",
],
+ host_supported: true,
backend: {
java: {
enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources
diff --git a/apex/statsd/framework/test/Android.bp b/apex/statsd/framework/test/Android.bp
index b113d595b57c..5cc5647bc760 100644
--- a/apex/statsd/framework/test/Android.bp
+++ b/apex/statsd/framework/test/Android.bp
@@ -14,12 +14,8 @@
android_test {
name: "FrameworkStatsdTest",
- platform_apis: true,
- srcs: [
- // TODO(b/147705194): Use framework-statsd as a lib dependency instead.
- ":framework-statsd-sources",
- "**/*.java",
- ],
+ sdk_version: "module_current",
+ srcs: [ "**/*.java" ],
manifest: "AndroidManifest.xml",
static_libs: [
"androidx.test.rules",
@@ -28,9 +24,10 @@ android_test {
libs: [
"android.test.runner.stubs",
"android.test.base.stubs",
+ "framework-statsd.impl",
],
test_suites: [
"device-tests",
"mts",
],
-} \ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index 0744894f522a..651cda564ee9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -49106,6 +49106,7 @@ package android.telephony.ims.feature {
}
public static class MmTelFeature.MmTelCapabilities {
+ method public final boolean isCapable(int);
field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 1afe4493e33c..360e44ff055c 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -1,4 +1,12 @@
// Signature format: 2.0
+package android.app {
+
+ public class AppOpsManager {
+ field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
+ }
+
+}
+
package android.content.rollback {
public class RollbackManagerFrameworkInitializer {
@@ -21,24 +29,6 @@ package android.graphics {
package android.net {
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
public final class TetheringConstants {
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
@@ -58,69 +48,15 @@ package android.net {
method @NonNull public String[] getTetheringErroredIfaces();
method public boolean isTetheringSupported();
method public boolean isTetheringSupported(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
method @Deprecated public int tether(@NonNull String);
- method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
method @Deprecated public int untether(@NonNull String);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
}
public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
}
public static class TetheringManager.TetheringInterfaceRegexps {
@@ -129,22 +65,6 @@ package android.net {
method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission("android.permission.TETHER_PRIVILEGED") public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
}
package android.os {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6a04450817ab..fa4543001f90 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -12250,7 +12250,6 @@ package android.telephony.ims.feature {
ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
ctor public MmTelFeature.MmTelCapabilities(int);
method public final void addCapabilities(int);
- method public final boolean isCapable(int);
method public final void removeCapabilities(int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index ab0761374570..dc6626586efa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4697,7 +4697,6 @@ package android.telephony.ims.feature {
ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
ctor public MmTelFeature.MmTelCapabilities(int);
method public final void addCapabilities(int);
- method public final boolean isCapable(int);
method public final void removeCapabilities(int);
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 124f815f51f0..1579715727ac 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -171,7 +171,8 @@ cc_library_static {
export_generated_headers: ["statslog_statsdtest.h"],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
}
cc_library_static {
@@ -185,7 +186,11 @@ cc_library_static {
],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatspull",
+ ],
}
// =========
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 02c0d933b3cd..fc74fec45e47 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -583,7 +583,8 @@ message Atom {
SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
BlobInfo blob_info = 10081 [(module) = "framework"];
- DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"];
+ DataUsageBytesTransfer data_usage_bytes_transfer =
+ 10082 [(module) = "framework", (truncate_timestamp) = true];
BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered =
10083 [(module) = "framework"];
DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"];
@@ -5191,6 +5192,12 @@ message DataUsageBytesTransfer {
// record is combined across opportunistic data subscriptions.
// See {@link SubscriptionManager#setOpportunistic}.
optional DataSubscriptionState opportunistic_data_sub = 10;
+
+ // Indicate whether NR is connected, server side could use this with RAT type to determine if
+ // the record is for 5G NSA (Non Stand Alone) mode, where the primary cell is still LTE and
+ // network allocates a secondary 5G cell so telephony reports RAT = LTE along with NR state as
+ // connected.
+ optional bool is_nr_connected = 11;
}
/**
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 5987a723a421..9b684f1248c5 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -733,6 +733,11 @@ bool getDoubleOrLong(const LogEvent& event, const Matcher& matcher, Value& ret)
return false;
}
+bool ValueMetricProducer::multipleBucketsSkipped(const int64_t numBucketsForward) {
+ // Skip buckets if this is a pulled metric or a pushed metric that is diffed.
+ return numBucketsForward > 1 && (mIsPulled || mUseDiff);
+}
+
void ValueMetricProducer::onMatchedLogEventInternalLocked(
const size_t matcherIndex, const MetricDimensionKey& eventKey,
const ConditionKey& conditionKey, bool condition, const LogEvent& event,
@@ -910,8 +915,9 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked(
interval.sampleSize += 1;
}
- // Only trigger the tracker if all intervals are correct
- if (useAnomalyDetection) {
+ // Only trigger the tracker if all intervals are correct and we have not skipped the bucket due
+ // to MULTIPLE_BUCKETS_SKIPPED.
+ if (useAnomalyDetection && !multipleBucketsSkipped(calcBucketsForwardCount(eventTimeNs))) {
// TODO: propgate proper values down stream when anomaly support doubles
long wholeBucketVal = intervals[0].value.long_value;
auto prev = mCurrentFullBucket.find(eventKey);
@@ -961,9 +967,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
int64_t bucketEndTime = fullBucketEndTimeNs;
int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
- // Skip buckets if this is a pulled metric or a pushed metric that is diffed.
- if (numBucketsForward > 1 && (mIsPulled || mUseDiff)) {
-
+ if (multipleBucketsSkipped(numBucketsForward)) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
// Something went wrong. Maybe the device was sleeping for a long time. It is better
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index b359af745c91..e72002e88533 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -219,6 +219,8 @@ private:
void pullAndMatchEventsLocked(const int64_t timestampNs);
+ bool multipleBucketsSkipped(const int64_t numBucketsForward);
+
void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 97757afaf226..98892507e78d 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1081,6 +1081,49 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
std::ceil(1.0 * event6.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
}
+TEST(ValueMetricProducerTest, TestAnomalyDetectionMultipleBucketsSkipped) {
+ sp<AlarmMonitor> alarmMonitor;
+ Alert alert;
+ alert.set_id(101);
+ alert.set_metric_id(metricId);
+ alert.set_trigger_if_sum_gt(100);
+ alert.set_num_buckets(1);
+ const int32_t refPeriodSec = 3;
+ alert.set_refractory_period_secs(refPeriodSec);
+
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 1); // Condition change to true time.
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 0));
+ return true;
+ }))
+ .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs,
+ vector<std::shared_ptr<LogEvent>>* data) {
+ EXPECT_EQ(eventTimeNs,
+ bucket3StartTimeNs + 100); // Condition changed to false time.
+ data->clear();
+ data->push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 100, 120));
+ return true;
+ }));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
+ sp<AnomalyTracker> anomalyTracker = valueProducer->addAnomalyTracker(alert, alarmMonitor);
+
+ valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+
+ // multiple buckets should be skipped here.
+ valueProducer->onConditionChanged(false, bucket3StartTimeNs + 100);
+
+ // No alert is fired when multiple buckets are skipped.
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+}
+
// Test value metric no condition, the pull on bucket boundary come in time and too late
TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index ea7b94502521..ab2f42b97e3b 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -42424,10 +42424,6 @@ Landroid/hardware/camera2/impl/CameraMetadataNative$Key;
Landroid/hardware/camera2/impl/CameraMetadataNative;
Landroid/hardware/camera2/impl/GetCommand;
Landroid/hardware/camera2/impl/SetCommand;
-Landroid/hardware/camera2/legacy/LegacyCameraDevice;
-Landroid/hardware/camera2/legacy/LegacyExceptionUtils$BufferQueueAbandonedException;
-Landroid/hardware/camera2/legacy/LegacyMetadataMapper;
-Landroid/hardware/camera2/legacy/PerfMeasurement;
Landroid/hardware/camera2/marshal/MarshalHelpers;
Landroid/hardware/camera2/marshal/MarshalQueryable;
Landroid/hardware/camera2/marshal/MarshalRegistry$MarshalToken;
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 0bff3aa16204..881cfa335700 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -2297,10 +2297,6 @@ android.hardware.camera2.impl.CameraMetadataNative$Key
android.hardware.camera2.impl.CameraMetadataNative
android.hardware.camera2.impl.GetCommand
android.hardware.camera2.impl.SetCommand
-android.hardware.camera2.legacy.LegacyCameraDevice
-android.hardware.camera2.legacy.LegacyExceptionUtils$BufferQueueAbandonedException
-android.hardware.camera2.legacy.LegacyMetadataMapper
-android.hardware.camera2.legacy.PerfMeasurement
android.hardware.camera2.marshal.MarshalHelpers
android.hardware.camera2.marshal.MarshalQueryable
android.hardware.camera2.marshal.MarshalRegistry$MarshalToken
diff --git a/core/java/android/annotation/SystemApi.java b/core/java/android/annotation/SystemApi.java
index 4ac00983af13..a468439c8e74 100644
--- a/core/java/android/annotation/SystemApi.java
+++ b/core/java/android/annotation/SystemApi.java
@@ -23,7 +23,6 @@ import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PACKAGE;
import static java.lang.annotation.ElementType.TYPE;
-import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -41,7 +40,6 @@ import java.lang.annotation.Target;
*/
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
-@Repeatable(SystemApi.Container.class) // TODO(b/146727827): make this non-repeatable
public @interface SystemApi {
enum Client {
/**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 505cfe7e6d28..7ba50cadd959 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -387,8 +387,8 @@ public abstract class ActivityManagerInternal {
/** Returns true if the given uid is the app in the foreground. */
public abstract boolean isAppForeground(int uid);
- /** Returns true if the given uid is currently marked 'bad' */
- public abstract boolean isAppBad(ApplicationInfo info);
+ /** Returns true if the given process name and uid is currently marked 'bad' */
+ public abstract boolean isAppBad(String processName, int uid);
/** Remove pending backup for the given userId. */
public abstract void clearPendingBackup(@UserIdInt int userId);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d642f218cb71..b40dd0053846 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -732,6 +732,10 @@ public class AppOpsManager {
public static final int SAMPLING_STRATEGY_BOOT_TIME_SAMPLING =
FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__BOOT_TIME_SAMPLING;
+ /** @hide */
+ public static final int SAMPLING_STRATEGY_UNIFORM_OPS =
+ FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__UNIFORM_OPS;
+
/**
* Strategies used for message sampling
* @hide
@@ -741,7 +745,8 @@ public class AppOpsManager {
SAMPLING_STRATEGY_DEFAULT,
SAMPLING_STRATEGY_UNIFORM,
SAMPLING_STRATEGY_RARELY_USED,
- SAMPLING_STRATEGY_BOOT_TIME_SAMPLING
+ SAMPLING_STRATEGY_BOOT_TIME_SAMPLING,
+ SAMPLING_STRATEGY_UNIFORM_OPS
})
public @interface SamplingStrategy {}
@@ -1456,8 +1461,12 @@ public class AppOpsManager {
/**
* AppOp granted to apps that we are started via {@code am instrument -e --no-isolated-storage}
*
+ * <p>MediaProvider is the only component (outside of system server) that should care about this
+ * app op, hence {@code SystemApi.Client.MODULE_LIBRARIES}.
+ *
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
/** {@link #sAppOpsToNote} not initialized yet for this op */
@@ -8350,7 +8359,7 @@ public class AppOpsManager {
* @hide
*/
private static boolean isCollectingStackTraces() {
- if (sConfig.getSampledOpCode() == OP_NONE &&
+ if (sConfig.getSampledOpCode() == OP_NONE && sConfig.getAcceptableLeftDistance() == 0 &&
sConfig.getExpirationTimeSinceBootMillis() >= SystemClock.elapsedRealtime()) {
return false;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index ca759e9fc6fa..dedd8705ef55 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2687,7 +2687,7 @@ public class ApplicationPackageManager extends PackageManager {
public void addPreferredActivity(IntentFilter filter,
int match, ComponentName[] set, ComponentName activity) {
try {
- mPM.addPreferredActivity(filter, match, set, activity, getUserId());
+ mPM.addPreferredActivity(filter, match, set, activity, getUserId(), false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2697,7 +2697,7 @@ public class ApplicationPackageManager extends PackageManager {
public void addPreferredActivityAsUser(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
try {
- mPM.addPreferredActivity(filter, match, set, activity, userId);
+ mPM.addPreferredActivity(filter, match, set, activity, userId, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2734,6 +2734,16 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public void addUniquePreferredActivity(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity) {
+ try {
+ mPM.addPreferredActivity(filter, match, set, activity, getUserId(), true);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
try {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 4b0d2f86ad34..bca6f39e1ded 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -175,14 +175,33 @@ import java.util.concurrent.atomic.AtomicLong;
*
* Caching can be disabled completely by initializing {@code sEnabled} to false and rebuilding.
*
+ * To test a binder cache, create one or more tests that exercise the binder method. This
+ * should be done twice: once with production code and once with a special image that sets
+ * {@code DEBUG} and {@code VERIFY} true. In the latter case, verify that no cache
+ * inconsistencies are reported. If a cache inconsistency is reported, however, it might be a
+ * false positive. This happens if the server side data can be read and written non-atomically
+ * with respect to cache invalidation.
+ *
* @param <Query> The class used to index cache entries: must be hashable and comparable
* @param <Result> The class holding cache entries; use a boxed primitive if possible
*
* {@hide}
*/
public abstract class PropertyInvalidatedCache<Query, Result> {
- private static final long NONCE_UNSET = 0;
- private static final long NONCE_DISABLED = -1;
+ /**
+ * Reserved nonce values. The code is written assuming that these
+ * values are contiguous.
+ */
+ private static final int NONCE_UNSET = 0;
+ private static final int NONCE_DISABLED = 1;
+ private static final int NONCE_CORKED = 2;
+ private static final int NONCE_RESERVED = NONCE_CORKED + 1;
+
+ /**
+ * The names of the nonces
+ */
+ private static final String[] sNonceName =
+ new String[]{ "unset", "disabled", "corked" };
private static final String TAG = "PropertyInvalidatedCache";
private static final boolean DEBUG = false;
@@ -195,11 +214,28 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
@GuardedBy("mLock")
private long mMisses = 0;
+ @GuardedBy("mLock")
+ private long mMissDisabled[] = new long[]{ 0, 0, 0 };
+
+ @GuardedBy("mLock")
+ private long mMissOverflow = 0;
+
+ @GuardedBy("mLock")
+ private long mHighWaterMark = 0;
+
// Most invalidation is done in a static context, so the counters need to be accessible.
@GuardedBy("sCorkLock")
private static final HashMap<String, Long> sInvalidates = new HashMap<>();
/**
+ * Record the number of invalidate or cork calls that were nops because
+ * the cache was already corked. This is static because invalidation is
+ * done in a static context.
+ */
+ @GuardedBy("sCorkLock")
+ private static final HashMap<String, Long> sCorkedInvalidates = new HashMap<>();
+
+ /**
* If sEnabled is false then all cache operations are stubbed out. Set
* it to false inside test processes.
*/
@@ -271,7 +307,15 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
true /* LRU access order */) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
- return size() > maxEntries;
+ final int size = size();
+ if (size > mHighWaterMark) {
+ mHighWaterMark = size;
+ }
+ if (size > maxEntries) {
+ mMissOverflow++;
+ return true;
+ }
+ return false;
}
};
synchronized (sCorkLock) {
@@ -363,14 +407,21 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
// Let access to mDisabled race: it's atomic anyway.
long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED;
for (;;) {
- if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET) {
+ if (currentNonce == NONCE_DISABLED || currentNonce == NONCE_UNSET ||
+ currentNonce == NONCE_CORKED) {
+ if (!mDisabled) {
+ // Do not bother collecting statistics if the cache is
+ // locally disabled.
+ synchronized (mLock) {
+ mMissDisabled[(int) currentNonce]++;
+ }
+ }
+
if (DEBUG) {
if (!mDisabled) {
Log.d(TAG, String.format(
"cache %s %s for %s",
- cacheName(),
- currentNonce == NONCE_DISABLED ? "disabled" : "unset",
- queryToString(query)));
+ cacheName(), sNonceName[(int) currentNonce], queryToString(query)));
}
}
return recompute(query);
@@ -383,10 +434,10 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
if (cachedResult != null) mHits++;
} else {
if (DEBUG) {
- Log.d(TAG,
- String.format("clearing cache %s because nonce changed [%s] -> [%s]",
- cacheName(),
- mLastSeenNonce, currentNonce));
+ Log.d(TAG, String.format(
+ "clearing cache %s of %d entries because nonce changed [%s] -> [%s]",
+ cacheName(), mCache.size(),
+ mLastSeenNonce, currentNonce));
}
mCache.clear();
mLastSeenNonce = currentNonce;
@@ -517,6 +568,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
if (DEBUG) {
Log.d(TAG, "ignoring invalidation due to cork: " + name);
}
+ final long count = sCorkedInvalidates.getOrDefault(name, (long) 0);
+ sCorkedInvalidates.put(name, count + 1);
return;
}
invalidateCacheLocked(name);
@@ -538,7 +591,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
long newValue;
do {
newValue = NoPreloadHolder.next();
- } while (newValue == NONCE_UNSET || newValue == NONCE_DISABLED);
+ } while (newValue >= 0 && newValue < NONCE_RESERVED);
final String newValueString = Long.toString(newValue);
if (DEBUG) {
Log.d(TAG,
@@ -567,13 +620,21 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* @param name Name of the cache-key property to cork
*/
public static void corkInvalidations(@NonNull String name) {
+ if (!sEnabled) {
+ if (DEBUG) {
+ Log.w(TAG, String.format(
+ "cache cork %s suppressed", name));
+ }
+ return;
+ }
+
synchronized (sCorkLock) {
int numberCorks = sCorks.getOrDefault(name, 0);
if (DEBUG) {
Log.d(TAG, String.format("corking %s: numberCorks=%s", name, numberCorks));
}
- // If we're the first ones to cork this cache, set the cache to the unset state so
+ // If we're the first ones to cork this cache, set the cache to the corked state so
// existing caches talk directly to their services while we've corked updates.
// Make sure we don't clobber a disabled cache value.
@@ -584,8 +645,11 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
if (numberCorks == 0) {
final long nonce = SystemProperties.getLong(name, NONCE_UNSET);
if (nonce != NONCE_UNSET && nonce != NONCE_DISABLED) {
- SystemProperties.set(name, Long.toString(NONCE_UNSET));
+ SystemProperties.set(name, Long.toString(NONCE_CORKED));
}
+ } else {
+ final long count = sCorkedInvalidates.getOrDefault(name, (long) 0);
+ sCorkedInvalidates.put(name, count + 1);
}
sCorks.put(name, numberCorks + 1);
if (DEBUG) {
@@ -602,6 +666,14 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* @param name Name of the cache-key property to uncork
*/
public static void uncorkInvalidations(@NonNull String name) {
+ if (!sEnabled) {
+ if (DEBUG) {
+ Log.w(TAG, String.format(
+ "cache uncork %s suppressed", name));
+ }
+ return;
+ }
+
synchronized (sCorkLock) {
int numberCorks = sCorks.getOrDefault(name, 0);
if (DEBUG) {
@@ -729,8 +801,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
boolean nonceChanged = (getCurrentNonce() != mLastSeenNonce);
if (!nonceChanged && !debugCompareQueryResults(proposedResult, resultToCompare)) {
Log.e(TAG, String.format(
- "cache %s inconsistent for %s",
- cacheName(), queryToString(query)));
+ "cache %s inconsistent for %s is %s should be %s",
+ cacheName(), queryToString(query),
+ proposedResult, resultToCompare));
}
// Always return the "true" result in verification mode.
return resultToCompare;
@@ -784,18 +857,23 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
private void dumpContents(PrintWriter pw, String[] args) {
long invalidateCount;
-
+ long corkedInvalidates;
synchronized (sCorkLock) {
invalidateCount = sInvalidates.getOrDefault(mPropertyName, (long) 0);
+ corkedInvalidates = sCorkedInvalidates.getOrDefault(mPropertyName, (long) 0);
}
synchronized (mLock) {
pw.println(String.format(" Cache Property Name: %s", cacheName()));
- pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d",
- mHits, mMisses, invalidateCount));
+ pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d, Overflows: %d",
+ mHits, mMisses, invalidateCount, mMissOverflow));
+ pw.println(String.format(" Miss-corked: %d, Miss-unset: %d, Miss-other: %d," +
+ " CorkedInvalidates: %d",
+ mMissDisabled[NONCE_CORKED], mMissDisabled[NONCE_UNSET],
+ mMissDisabled[NONCE_DISABLED], corkedInvalidates));
pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce));
- pw.println(String.format(" Current Size: %d, Max Size: %d",
- mCache.entrySet().size(), mMaxEntries));
+ pw.println(String.format(" Current Size: %d, Max Size: %d, HW Mark: %d",
+ mCache.size(), mMaxEntries, mHighWaterMark));
pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true"));
Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet();
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 4f5c4feb3684..df11d3adac01 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -52,6 +52,18 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
+ /**
+ * Action to notify read status changed
+ */
+ public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
+ "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
+
+ /**
+ * Action to notify deleted status changed
+ */
+ public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
+ "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
+
/* Extras used in ACTION_MESSAGE_RECEIVED intent.
* NOTE: HANDLE is only valid for a single session with the device. */
public static final String EXTRA_MESSAGE_HANDLE =
@@ -65,6 +77,25 @@ public final class BluetoothMapClient implements BluetoothProfile {
public static final String EXTRA_SENDER_CONTACT_NAME =
"android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
+ /**
+ * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED
+ * Contains the MAP message deleted status
+ * Possible values are:
+ * true: deleted
+ * false: undeleted
+ */
+ public static final String EXTRA_MESSAGE_DELETED_STATUS =
+ "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS";
+
+ /**
+ * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED
+ * Possible values are:
+ * 0: failure
+ * 1: success
+ */
+ public static final String EXTRA_RESULT_CODE =
+ "android.bluetooth.device.extra.RESULT_CODE";
+
/** There was an error trying to obtain the state */
public static final int STATE_ERROR = -1;
@@ -75,6 +106,12 @@ public final class BluetoothMapClient implements BluetoothProfile {
private static final int UPLOADING_FEATURE_BITMASK = 0x08;
+ /** Parameters in setMessageStatus */
+ public static final int UNREAD = 0;
+ public static final int READ = 1;
+ public static final int UNDELETED = 2;
+ public static final int DELETED = 3;
+
private BluetoothAdapter mAdapter;
private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
@@ -405,6 +442,38 @@ public final class BluetoothMapClient implements BluetoothProfile {
return false;
}
+ /**
+ * Set message status of message on MSE
+ * <p>
+ * When read status changed, the result will be published via
+ * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED}
+ * When deleted status changed, the result will be published via
+ * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED}
+ *
+ * @param device Bluetooth device
+ * @param handle message handle
+ * @param status <code>UNREAD</code> for "unread", <code>READ</code> for
+ * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for
+ * "deleted", otherwise return error
+ * @return <code>true</code> if request has been sent, <code>false</code> on error
+ *
+ */
+ @RequiresPermission(Manifest.permission.READ_SMS)
+ public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
+ if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")");
+ final IBluetoothMapClient service = getService();
+ if (service != null && isEnabled() && isValidDevice(device) && handle != null &&
+ (status == READ || status == UNREAD || status == UNDELETED || status == DELETED)) {
+ try {
+ return service.setMessageStatus(device, handle, status);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+ return false;
+ }
+
private boolean isEnabled() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index f257326904fd..6a8dd81051eb 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -261,7 +261,7 @@ interface IPackageManager {
in IntentFilter filter, int match, in ComponentName activity);
void addPreferredActivity(in IntentFilter filter, int match,
- in ComponentName[] set, in ComponentName activity, int userId);
+ in ComponentName[] set, in ComponentName activity, int userId, boolean removeExisting);
@UnsupportedAppUsage
void replacePreferredActivity(in IntentFilter filter, int match,
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f533760de84d..42a610700051 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -6763,6 +6763,17 @@ public abstract class PackageManager {
public abstract void clearPackagePreferredActivities(@NonNull String packageName);
/**
+ * Same as {@link #addPreferredActivity(IntentFilter, int, ComponentName[], ComponentName)},
+ * but removes all existing entries that match this filter.
+ * @hide
+ */
+ public void addUniquePreferredActivity(@NonNull IntentFilter filter, int match,
+ @Nullable ComponentName[] set, @NonNull ComponentName activity) {
+ throw new UnsupportedOperationException(
+ "addUniquePreferredActivity not implemented in subclass");
+ }
+
+ /**
* Retrieve all preferred activities, previously added with
* {@link #addPreferredActivity}, that are
* currently registered with the system.
@@ -8179,7 +8190,7 @@ public abstract class PackageManager {
private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>
sPackageInfoCache =
new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>(
- 16, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
+ 32, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
@Override
protected PackageInfo recompute(PackageInfoQuery query) {
return getPackageInfoAsUserUncached(
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6a9e0aa047d1..9480d369065d 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -45,7 +45,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
-import android.app.UiModeManager;
import android.app.WindowConfiguration;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.LocaleProto;
@@ -928,7 +927,13 @@ public final class Configuration implements Parcelable, Comparable<Configuration
fontScale = o.fontScale;
mcc = o.mcc;
mnc = o.mnc;
- locale = o.locale == null ? null : (Locale) o.locale.clone();
+ if (o.locale == null) {
+ locale = null;
+ } else if (!o.locale.equals(locale)) {
+ // Only clone a new Locale instance if we need to: the clone() is
+ // both CPU and GC intensive.
+ locale = (Locale) o.locale.clone();
+ }
o.fixUpLocaleList();
mLocaleList = o.mLocaleList;
userSetLocale = o.userSetLocale;
@@ -1624,7 +1629,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration
if ((mask & ActivityInfo.CONFIG_LOCALE) != 0) {
mLocaleList = delta.mLocaleList;
if (!mLocaleList.isEmpty()) {
- locale = (Locale) delta.locale.clone();
+ if (!delta.locale.equals(locale)) {
+ // Don't churn a new Locale clone unless we're actually changing it
+ locale = (Locale) delta.locale.clone();
+ }
}
}
if ((mask & ActivityInfo.CONFIG_LAYOUT_DIRECTION) != 0) {
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 25279b31b5d1..215990568fbf 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -249,14 +249,10 @@ public class Camera {
public static final int CAMERA_HAL_API_VERSION_1_0 = 0x100;
/**
- * A constant meaning the normal camera connect/open will be used.
- */
- private static final int CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2;
-
- /**
- * Used to indicate HAL version un-specified.
+ * Camera HAL device API version 3.0
+ * @hide
*/
- private static final int CAMERA_HAL_API_VERSION_UNSPECIFIED = -1;
+ public static final int CAMERA_HAL_API_VERSION_3_0 = 0x300;
/**
* Hardware face detection. It does not use much CPU.
@@ -427,7 +423,7 @@ public class Camera {
* Creates a new Camera object to access a particular hardware camera with
* given hal API version. If the same camera is opened by other applications
* or the hal API version is not supported by this device, this will throw a
- * RuntimeException.
+ * RuntimeException. As of Android 12, HAL version 1 is no longer supported.
* <p>
* You must call {@link #release()} when you are done using the camera,
* otherwise it will remain locked and be unavailable to other applications.
@@ -463,49 +459,14 @@ public class Camera {
*/
@UnsupportedAppUsage
public static Camera openLegacy(int cameraId, int halVersion) {
- if (halVersion < CAMERA_HAL_API_VERSION_1_0) {
- throw new IllegalArgumentException("Invalid HAL version " + halVersion);
+ if (halVersion < CAMERA_HAL_API_VERSION_3_0) {
+ throw new IllegalArgumentException("Unsupported HAL version " + halVersion);
}
- return new Camera(cameraId, halVersion);
- }
-
- /**
- * Create a legacy camera object.
- *
- * @param cameraId The hardware camera to access, between 0 and
- * {@link #getNumberOfCameras()}-1.
- * @param halVersion The HAL API version this camera device to be opened as.
- */
- private Camera(int cameraId, int halVersion) {
- int err = cameraInitVersion(cameraId, halVersion);
- if (checkInitErrors(err)) {
- if (err == -EACCES) {
- throw new RuntimeException("Fail to connect to camera service");
- } else if (err == -ENODEV) {
- throw new RuntimeException("Camera initialization failed");
- } else if (err == -ENOSYS) {
- throw new RuntimeException("Camera initialization failed because some methods"
- + " are not implemented");
- } else if (err == -EOPNOTSUPP) {
- throw new RuntimeException("Camera initialization failed because the hal"
- + " version is not supported by this device");
- } else if (err == -EINVAL) {
- throw new RuntimeException("Camera initialization failed because the input"
- + " arugments are invalid");
- } else if (err == -EBUSY) {
- throw new RuntimeException("Camera initialization failed because the camera"
- + " device was already opened");
- } else if (err == -EUSERS) {
- throw new RuntimeException("Camera initialization failed because the max"
- + " number of camera devices were already opened");
- }
- // Should never hit this.
- throw new RuntimeException("Unknown camera error");
- }
+ return new Camera(cameraId);
}
- private int cameraInitVersion(int cameraId, int halVersion) {
+ private int cameraInit(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
@@ -523,35 +484,13 @@ public class Camera {
mEventHandler = null;
}
- return native_setup(new WeakReference<Camera>(this), cameraId, halVersion,
+ return native_setup(new WeakReference<Camera>(this), cameraId,
ActivityThread.currentOpPackageName());
}
- private int cameraInitNormal(int cameraId) {
- return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
- }
-
- /**
- * Connect to the camera service using #connectLegacy
- *
- * <p>
- * This acts the same as normal except that it will return
- * the detailed error code if open fails instead of
- * converting everything into {@code NO_INIT}.</p>
- *
- * <p>Intended to use by the camera2 shim only, do <i>not</i> use this for other code.</p>
- *
- * @return a detailed errno error code, or {@code NO_ERROR} on success
- *
- * @hide
- */
- public int cameraInitUnspecified(int cameraId) {
- return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_UNSPECIFIED);
- }
-
/** used by Camera#open, Camera#open(int) */
Camera(int cameraId) {
- int err = cameraInitNormal(cameraId);
+ int err = cameraInit(cameraId);
if (checkInitErrors(err)) {
if (err == -EACCES) {
throw new RuntimeException("Fail to connect to camera service");
@@ -616,8 +555,7 @@ public class Camera {
}
@UnsupportedAppUsage
- private native final int native_setup(Object camera_this, int cameraId, int halVersion,
- String packageName);
+ private native int native_setup(Object cameraThis, int cameraId, String packageName);
private native final void native_release();
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 7f834afd7b30..8469f5f981ed 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -23,14 +23,11 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
-import android.hardware.CameraInfo;
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
import android.hardware.camera2.impl.CameraDeviceImpl;
import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.legacy.CameraDeviceUserShim;
-import android.hardware.camera2.legacy.LegacyMetadataMapper;
import android.hardware.camera2.params.SessionConfiguration;
import android.hardware.camera2.utils.CameraIdAndSessionConfiguration;
import android.hardware.camera2.utils.ConcurrentCameraIdCombination;
@@ -405,10 +402,6 @@ public final class CameraManager {
throw new IllegalArgumentException("No cameras available on device");
}
synchronized (mLock) {
- /*
- * Get the camera characteristics from the camera service directly if it supports it,
- * otherwise get them from the legacy shim instead.
- */
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -417,34 +410,18 @@ public final class CameraManager {
try {
Size displaySize = getDisplaySize();
- // First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
- // exception in case cameraId is a hidden physical camera.
- if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
- // Legacy backwards compatibility path; build static info from the camera
- // parameters
- int id = Integer.parseInt(cameraId);
-
- String parameters = cameraService.getLegacyParameters(id);
-
- CameraInfo info = cameraService.getCameraInfo(id);
-
- characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info,
- id, displaySize);
- } else {
- // Normal path: Get the camera characteristics directly from the camera service
- CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
- try {
- info.setCameraId(Integer.parseInt(cameraId));
- } catch (NumberFormatException e) {
- // For external camera, reaching here is expected.
- Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer");
- }
- boolean hasConcurrentStreams =
- CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId);
- info.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
- info.setDisplaySize(displaySize);
- characteristics = new CameraCharacteristics(info);
+ CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
+ try {
+ info.setCameraId(Integer.parseInt(cameraId));
+ } catch (NumberFormatException e) {
+ Log.v(TAG, "Failed to parse camera Id " + cameraId + " to integer");
}
+ boolean hasConcurrentStreams =
+ CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId);
+ info.setHasMandatoryConcurrentStreams(hasConcurrentStreams);
+ info.setDisplaySize(displaySize);
+ characteristics = new CameraCharacteristics(info);
+
} catch (ServiceSpecificException e) {
throwAsPublicException(e);
} catch (RemoteException e) {
@@ -500,30 +477,14 @@ public final class CameraManager {
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
- if (supportsCamera2ApiLocked(cameraId)) {
- // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
- ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
- if (cameraService == null) {
- throw new ServiceSpecificException(
- ICameraService.ERROR_DISCONNECTED,
- "Camera service is currently unavailable");
- }
- cameraUser = cameraService.connectDevice(callbacks, cameraId,
- mContext.getOpPackageName(), mContext.getAttributionTag(), uid);
- } else {
- // Use legacy camera implementation for HAL1 devices
- int id;
- try {
- id = Integer.parseInt(cameraId);
- } catch (NumberFormatException e) {
- throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
- + cameraId);
- }
-
- Log.i(TAG, "Using legacy camera HAL.");
- cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id,
- getDisplaySize());
+ ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+ if (cameraService == null) {
+ throw new ServiceSpecificException(
+ ICameraService.ERROR_DISCONNECTED,
+ "Camera service is currently unavailable");
}
+ cameraUser = cameraService.connectDevice(callbacks, cameraId,
+ mContext.getOpPackageName(), mContext.getAttributionTag(), uid);
} catch (ServiceSpecificException e) {
if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
throw new AssertionError("Should've gone down the shim path");
@@ -1021,44 +982,6 @@ public final class CameraManager {
}
/**
- * Queries the camera service if it supports the camera2 api directly, or needs a shim.
- *
- * @param cameraId a non-{@code null} camera identifier
- * @return {@code false} if the legacy shim needs to be used, {@code true} otherwise.
- */
- private boolean supportsCamera2ApiLocked(String cameraId) {
- return supportsCameraApiLocked(cameraId, API_VERSION_2);
- }
-
- /**
- * Queries the camera service if it supports a camera api directly, or needs a shim.
- *
- * @param cameraId a non-{@code null} camera identifier
- * @param apiVersion the version, i.e. {@code API_VERSION_1} or {@code API_VERSION_2}
- * @return {@code true} if connecting will work for that device version.
- */
- private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
- /*
- * Possible return values:
- * - NO_ERROR => CameraX API is supported
- * - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
- * - Remote exception => If the camera service died
- *
- * Anything else is an unexpected error we don't want to recover from.
- */
- try {
- ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
- // If no camera service, no support
- if (cameraService == null) return false;
-
- return cameraService.supportsCameraApi(cameraId, apiVersion);
- } catch (RemoteException e) {
- // Camera service is now down, no support for any API level
- }
- return false;
- }
-
- /**
* Queries the camera service if a cameraId is a hidden physical camera that belongs to a
* logical camera device.
*
diff --git a/core/java/android/hardware/camera2/legacy/BurstHolder.java b/core/java/android/hardware/camera2/legacy/BurstHolder.java
deleted file mode 100644
index 23efe15fc03b..000000000000
--- a/core/java/android/hardware/camera2/legacy/BurstHolder.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.camera2.CaptureRequest;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Immutable container for a burst of capture results.
- */
-public class BurstHolder {
- private static final String TAG = "BurstHolder";
- private final ArrayList<RequestHolder.Builder> mRequestBuilders;
- private final boolean mRepeating;
- private final int mRequestId;
-
- /**
- * Immutable container for a burst of capture results.
- *
- * @param requestId id of the burst request.
- * @param repeating true if this burst is repeating.
- * @param requests the array of {@link CaptureRequest}s for this burst.
- * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
- */
- public BurstHolder(int requestId, boolean repeating, CaptureRequest[] requests,
- Collection<Long> jpegSurfaceIds) {
- mRequestBuilders = new ArrayList<>();
- int i = 0;
- for (CaptureRequest r : requests) {
- mRequestBuilders.add(new RequestHolder.Builder(requestId, /*subsequenceId*/i,
- /*request*/r, repeating, jpegSurfaceIds));
- ++i;
- }
- mRepeating = repeating;
- mRequestId = requestId;
- }
-
- /**
- * Get the id of this request.
- */
- public int getRequestId() {
- return mRequestId;
- }
-
- /**
- * Return true if this repeating.
- */
- public boolean isRepeating() {
- return mRepeating;
- }
-
- /**
- * Return the number of requests in this burst sequence.
- */
- public int getNumberOfRequests() {
- return mRequestBuilders.size();
- }
-
- /**
- * Create a list of {@link RequestHolder} objects encapsulating the requests in this burst.
- *
- * @param frameNumber the starting framenumber for this burst.
- * @return the list of {@link RequestHolder} objects.
- */
- public List<RequestHolder> produceRequestHolders(long frameNumber) {
- ArrayList<RequestHolder> holders = new ArrayList<RequestHolder>();
- int i = 0;
- for (RequestHolder.Builder b : mRequestBuilders) {
- holders.add(b.build(frameNumber + i));
- ++i;
- }
- return holders;
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
deleted file mode 100644
index 89ecd5f1ce63..000000000000
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.os.Handler;
-import android.util.Log;
-
-/**
- * Emulates a the state of a single Camera2 device.
- *
- * <p>
- * This class acts as the state machine for a camera device. Valid state transitions are given
- * in the table below:
- * </p>
- *
- * <ul>
- * <li>{@code UNCONFIGURED -> CONFIGURING}</li>
- * <li>{@code CONFIGURING -> IDLE}</li>
- * <li>{@code IDLE -> CONFIGURING}</li>
- * <li>{@code IDLE -> CAPTURING}</li>
- * <li>{@code IDLE -> IDLE}</li>
- * <li>{@code CAPTURING -> IDLE}</li>
- * <li>{@code ANY -> ERROR}</li>
- * </ul>
- */
-public class CameraDeviceState {
- private static final String TAG = "CameraDeviceState";
- private static final boolean DEBUG = false;
-
- private static final int STATE_ERROR = 0;
- private static final int STATE_UNCONFIGURED = 1;
- private static final int STATE_CONFIGURING = 2;
- private static final int STATE_IDLE = 3;
- private static final int STATE_CAPTURING = 4;
-
- private static final String[] sStateNames = { "ERROR", "UNCONFIGURED", "CONFIGURING", "IDLE",
- "CAPTURING"};
-
- private int mCurrentState = STATE_UNCONFIGURED;
- private int mCurrentError = NO_CAPTURE_ERROR;
-
- private RequestHolder mCurrentRequest = null;
-
- private Handler mCurrentHandler = null;
- private CameraDeviceStateListener mCurrentListener = null;
-
- /**
- * Error code used by {@link #setCaptureStart} and {@link #setCaptureResult} to indicate that no
- * error has occurred.
- */
- public static final int NO_CAPTURE_ERROR = -1;
-
- /**
- * CameraDeviceStateListener callbacks to be called after state transitions.
- */
- public interface CameraDeviceStateListener {
- void onError(int errorCode, Object errorArg, RequestHolder holder);
- void onConfiguring();
- void onIdle();
- void onBusy();
- void onCaptureStarted(RequestHolder holder, long timestamp);
- void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
- void onRequestQueueEmpty();
- void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId);
- }
-
- /**
- * Transition to the {@code ERROR} state.
- *
- * <p>
- * The device cannot exit the {@code ERROR} state. If the device was not already in the
- * {@code ERROR} state, {@link CameraDeviceStateListener#onError(int, RequestHolder)} will be
- * called.
- * </p>
- *
- * @param error the error to set. Should be one of the error codes defined in
- * {@link CameraDeviceImpl.CameraDeviceCallbacks}.
- */
- public synchronized void setError(int error) {
- mCurrentError = error;
- doStateTransition(STATE_ERROR);
- }
-
- /**
- * Transition to the {@code CONFIGURING} state, or {@code ERROR} if in an invalid state.
- *
- * <p>
- * If the device was not already in the {@code CONFIGURING} state,
- * {@link CameraDeviceStateListener#onConfiguring()} will be called.
- * </p>
- *
- * @return {@code false} if an error has occurred.
- */
- public synchronized boolean setConfiguring() {
- doStateTransition(STATE_CONFIGURING);
- return mCurrentError == NO_CAPTURE_ERROR;
- }
-
- /**
- * Transition to the {@code IDLE} state, or {@code ERROR} if in an invalid state.
- *
- * <p>
- * If the device was not already in the {@code IDLE} state,
- * {@link CameraDeviceStateListener#onIdle()} will be called.
- * </p>
- *
- * @return {@code false} if an error has occurred.
- */
- public synchronized boolean setIdle() {
- doStateTransition(STATE_IDLE);
- return mCurrentError == NO_CAPTURE_ERROR;
- }
-
- /**
- * Transition to the {@code CAPTURING} state, or {@code ERROR} if in an invalid state.
- *
- * <p>
- * If the device was not already in the {@code CAPTURING} state,
- * {@link CameraDeviceStateListener#onCaptureStarted(RequestHolder)} will be called.
- * </p>
- *
- * @param request A {@link RequestHolder} containing the request for the current capture.
- * @param timestamp The timestamp of the capture start in nanoseconds.
- * @param captureError Report a recoverable error for a single request using a valid
- * error code for {@code ICameraDeviceCallbacks}, or
- * {@link #NO_CAPTURE_ERROR}
- * @return {@code false} if an error has occurred.
- */
- public synchronized boolean setCaptureStart(final RequestHolder request, long timestamp,
- int captureError) {
- mCurrentRequest = request;
- doStateTransition(STATE_CAPTURING, timestamp, captureError);
- return mCurrentError == NO_CAPTURE_ERROR;
- }
-
- /**
- * Set the result for a capture.
- *
- * <p>
- * If the device was in the {@code CAPTURING} state,
- * {@link CameraDeviceStateListener#onCaptureResult(CameraMetadataNative, RequestHolder)} will
- * be called with the given result, otherwise this will result in the device transitioning to
- * the {@code ERROR} state,
- * </p>
- *
- * @param request The {@link RequestHolder} request that created this result.
- * @param result The {@link CameraMetadataNative} result to set.
- * @param captureError Report a recoverable error for a single buffer or result using a valid
- * error code for {@code ICameraDeviceCallbacks}, or
- * {@link #NO_CAPTURE_ERROR}.
- * @param captureErrorArg An argument for some error captureError codes.
- * @return {@code false} if an error has occurred.
- */
- public synchronized boolean setCaptureResult(final RequestHolder request,
- final CameraMetadataNative result,
- final int captureError, final Object captureErrorArg) {
- if (mCurrentState != STATE_CAPTURING) {
- Log.e(TAG, "Cannot receive result while in state: " + mCurrentState);
- mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
- doStateTransition(STATE_ERROR);
- return mCurrentError == NO_CAPTURE_ERROR;
- }
-
- if (mCurrentHandler != null && mCurrentListener != null) {
- if (captureError != NO_CAPTURE_ERROR) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onError(captureError, captureErrorArg, request);
- }
- });
- } else {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onCaptureResult(result, request);
- }
- });
- }
- }
- return mCurrentError == NO_CAPTURE_ERROR;
- }
-
- public synchronized boolean setCaptureResult(final RequestHolder request,
- final CameraMetadataNative result) {
- return setCaptureResult(request, result, NO_CAPTURE_ERROR, /*errorArg*/null);
- }
-
- /**
- * Set repeating request error.
- *
- * <p>Repeating request has been stopped due to an error such as abandoned output surfaces.</p>
- *
- * @param lastFrameNumber Frame number of the last repeating request before it is stopped.
- * @param repeatingRequestId The ID of the repeating request being stopped
- */
- public synchronized void setRepeatingRequestError(final long lastFrameNumber,
- final int repeatingRequestId) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onRepeatingRequestError(lastFrameNumber, repeatingRequestId);
- }
- });
- }
-
- /**
- * Indicate that request queue (non-repeating) becomes empty.
- *
- * <p> Send notification that all non-repeating requests have been sent to camera device. </p>
- */
- public synchronized void setRequestQueueEmpty() {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onRequestQueueEmpty();
- }
- });
- }
-
- /**
- * Set the listener for state transition callbacks.
- *
- * @param handler handler on which to call the callbacks.
- * @param listener the {@link CameraDeviceStateListener} callbacks to call.
- */
- public synchronized void setCameraDeviceCallbacks(Handler handler,
- CameraDeviceStateListener listener) {
- mCurrentHandler = handler;
- mCurrentListener = listener;
- }
-
- private void doStateTransition(int newState) {
- doStateTransition(newState, /*timestamp*/0, NO_CAPTURE_ERROR);
- }
-
- private void doStateTransition(int newState, final long timestamp, final int error) {
- if (newState != mCurrentState) {
- String stateName = "UNKNOWN";
- if (newState >= 0 && newState < sStateNames.length) {
- stateName = sStateNames[newState];
- }
- Log.i(TAG, "Legacy camera service transitioning to state " + stateName);
- }
-
- // If we transitioned into a non-IDLE/non-ERROR state then mark the device as busy
- if(newState != STATE_ERROR && newState != STATE_IDLE) {
- if (mCurrentState != newState && mCurrentHandler != null &&
- mCurrentListener != null) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onBusy();
- }
- });
- }
- }
-
- switch(newState) {
- case STATE_ERROR:
- if (mCurrentState != STATE_ERROR && mCurrentHandler != null &&
- mCurrentListener != null) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onError(mCurrentError, /*errorArg*/null, mCurrentRequest);
- }
- });
- }
- mCurrentState = STATE_ERROR;
- break;
- case STATE_CONFIGURING:
- if (mCurrentState != STATE_UNCONFIGURED && mCurrentState != STATE_IDLE) {
- Log.e(TAG, "Cannot call configure while in state: " + mCurrentState);
- mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
- doStateTransition(STATE_ERROR);
- break;
- }
- if (mCurrentState != STATE_CONFIGURING && mCurrentHandler != null &&
- mCurrentListener != null) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onConfiguring();
- }
- });
- }
- mCurrentState = STATE_CONFIGURING;
- break;
- case STATE_IDLE:
- if (mCurrentState == STATE_IDLE) {
- break;
- }
-
- if (mCurrentState != STATE_CONFIGURING && mCurrentState != STATE_CAPTURING) {
- Log.e(TAG, "Cannot call idle while in state: " + mCurrentState);
- mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
- doStateTransition(STATE_ERROR);
- break;
- }
-
- if (mCurrentState != STATE_IDLE && mCurrentHandler != null &&
- mCurrentListener != null) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onIdle();
- }
- });
- }
- mCurrentState = STATE_IDLE;
- break;
- case STATE_CAPTURING:
- if (mCurrentState != STATE_IDLE && mCurrentState != STATE_CAPTURING) {
- Log.e(TAG, "Cannot call capture while in state: " + mCurrentState);
- mCurrentError = CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE;
- doStateTransition(STATE_ERROR);
- break;
- }
-
- if (mCurrentHandler != null && mCurrentListener != null) {
- if (error != NO_CAPTURE_ERROR) {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onError(error, /*errorArg*/null, mCurrentRequest);
- }
- });
- } else {
- mCurrentHandler.post(new Runnable() {
- @Override
- public void run() {
- mCurrentListener.onCaptureStarted(mCurrentRequest, timestamp);
- }
- });
- }
- }
- mCurrentState = STATE_CAPTURING;
- break;
- default:
- throw new IllegalStateException("Transition to unknown state: " + newState);
- }
- }
-
-
-}
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
deleted file mode 100644
index cf8cab2cbc44..000000000000
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.ICameraService;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.ICameraOfflineSession;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.CaptureResultExtras;
-import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.params.SessionConfiguration;
-import android.hardware.camera2.utils.SubmitInfo;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-import android.util.Size;
-import android.util.SparseArray;
-import android.view.Surface;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static android.system.OsConstants.EACCES;
-import static android.system.OsConstants.ENODEV;
-
-/**
- * Compatibility implementation of the Camera2 API binder interface.
- *
- * <p>
- * This is intended to be called from the same process as client
- * {@link android.hardware.camera2.CameraDevice}, and wraps a
- * {@link android.hardware.camera2.legacy.LegacyCameraDevice} that emulates Camera2 service using
- * the Camera1 API.
- * </p>
- *
- * <p>
- * Keep up to date with ICameraDeviceUser.aidl.
- * </p>
- */
-@SuppressWarnings("deprecation")
-public class CameraDeviceUserShim implements ICameraDeviceUser {
- private static final String TAG = "CameraDeviceUserShim";
-
- private static final boolean DEBUG = false;
- private static final int OPEN_CAMERA_TIMEOUT_MS = 5000; // 5 sec (same as api1 cts timeout)
-
- private final LegacyCameraDevice mLegacyDevice;
-
- private final Object mConfigureLock = new Object();
- private int mSurfaceIdCounter;
- private boolean mConfiguring;
- private final SparseArray<Surface> mSurfaces;
- private final CameraCharacteristics mCameraCharacteristics;
- private final CameraLooper mCameraInit;
- private final CameraCallbackThread mCameraCallbacks;
-
-
- protected CameraDeviceUserShim(int cameraId, LegacyCameraDevice legacyCamera,
- CameraCharacteristics characteristics, CameraLooper cameraInit,
- CameraCallbackThread cameraCallbacks) {
- mLegacyDevice = legacyCamera;
- mConfiguring = false;
- mSurfaces = new SparseArray<Surface>();
- mCameraCharacteristics = characteristics;
- mCameraInit = cameraInit;
- mCameraCallbacks = cameraCallbacks;
-
- mSurfaceIdCounter = 0;
- }
-
- private static int translateErrorsFromCamera1(int errorCode) {
- if (errorCode == -EACCES) {
- return ICameraService.ERROR_PERMISSION_DENIED;
- }
-
- return errorCode;
- }
-
- /**
- * Create a separate looper/thread for the camera to run on; open the camera.
- *
- * <p>Since the camera automatically latches on to the current thread's looper,
- * it's important that we have our own thread with our own looper to guarantee
- * that the camera callbacks get correctly posted to our own thread.</p>
- */
- private static class CameraLooper implements Runnable, AutoCloseable {
- private final int mCameraId;
- private Looper mLooper;
- private volatile int mInitErrors;
- private final Camera mCamera = Camera.openUninitialized();
- private final ConditionVariable mStartDone = new ConditionVariable();
- private final Thread mThread;
-
- /**
- * Spin up a new thread, immediately open the camera in the background.
- *
- * <p>Use {@link #waitForOpen} to block until the camera is finished opening.</p>
- *
- * @param cameraId numeric camera Id
- *
- * @see #waitForOpen
- */
- public CameraLooper(int cameraId) {
- mCameraId = cameraId;
-
- mThread = new Thread(this, "LegacyCameraLooper");
- mThread.start();
- }
-
- public Camera getCamera() {
- return mCamera;
- }
-
- @Override
- public void run() {
- // Set up a looper to be used by camera.
- Looper.prepare();
-
- // Save the looper so that we can terminate this thread
- // after we are done with it.
- mLooper = Looper.myLooper();
- mInitErrors = mCamera.cameraInitUnspecified(mCameraId);
- mStartDone.open();
- Looper.loop(); // Blocks forever until #close is called.
- }
-
- /**
- * Quit the looper safely; then join until the thread shuts down.
- */
- @Override
- public void close() {
- if (mLooper == null) {
- return;
- }
-
- mLooper.quitSafely();
- try {
- mThread.join();
- } catch (InterruptedException e) {
- throw new AssertionError(e);
- }
-
- mLooper = null;
- }
-
- /**
- * Block until the camera opens; then return its initialization error code (if any).
- *
- * @param timeoutMs timeout in milliseconds
- *
- * @return int error code
- *
- * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
- */
- public int waitForOpen(int timeoutMs) {
- // Block until the camera is open asynchronously
- if (!mStartDone.block(timeoutMs)) {
- Log.e(TAG, "waitForOpen - Camera failed to open after timeout of "
- + OPEN_CAMERA_TIMEOUT_MS + " ms");
- try {
- mCamera.release();
- } catch (RuntimeException e) {
- Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
- }
-
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
- }
-
- return mInitErrors;
- }
- }
-
- /**
- * A thread to process callbacks to send back to the camera client.
- *
- * <p>This effectively emulates one-way binder semantics when in the same process as the
- * callee.</p>
- */
- private static class CameraCallbackThread implements ICameraDeviceCallbacks {
- private static final int CAMERA_ERROR = 0;
- private static final int CAMERA_IDLE = 1;
- private static final int CAPTURE_STARTED = 2;
- private static final int RESULT_RECEIVED = 3;
- private static final int PREPARED = 4;
- private static final int REPEATING_REQUEST_ERROR = 5;
- private static final int REQUEST_QUEUE_EMPTY = 6;
-
- private final HandlerThread mHandlerThread;
- private Handler mHandler;
-
- private final ICameraDeviceCallbacks mCallbacks;
-
- public CameraCallbackThread(ICameraDeviceCallbacks callbacks) {
- mCallbacks = callbacks;
-
- mHandlerThread = new HandlerThread("LegacyCameraCallback");
- mHandlerThread.start();
- }
-
- public void close() {
- mHandlerThread.quitSafely();
- }
-
- @Override
- public void onDeviceError(final int errorCode, final CaptureResultExtras resultExtras) {
- Message msg = getHandler().obtainMessage(CAMERA_ERROR,
- /*arg1*/ errorCode, /*arg2*/ 0,
- /*obj*/ resultExtras);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onDeviceIdle() {
- Message msg = getHandler().obtainMessage(CAMERA_IDLE);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
- Message msg = getHandler().obtainMessage(CAPTURE_STARTED,
- /*arg1*/ (int) (timestamp & 0xFFFFFFFFL),
- /*arg2*/ (int) ( (timestamp >> 32) & 0xFFFFFFFFL),
- /*obj*/ resultExtras);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onResultReceived(final CameraMetadataNative result,
- final CaptureResultExtras resultExtras,
- PhysicalCaptureResultInfo physicalResults[]) {
- Object[] resultArray = new Object[] { result, resultExtras };
- Message msg = getHandler().obtainMessage(RESULT_RECEIVED,
- /*obj*/ resultArray);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onPrepared(int streamId) {
- Message msg = getHandler().obtainMessage(PREPARED,
- /*arg1*/ streamId, /*arg2*/ 0);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) {
- Object[] objArray = new Object[] { lastFrameNumber, repeatingRequestId };
- Message msg = getHandler().obtainMessage(REPEATING_REQUEST_ERROR,
- /*obj*/ objArray);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public void onRequestQueueEmpty() {
- Message msg = getHandler().obtainMessage(REQUEST_QUEUE_EMPTY,
- /* arg1 */ 0, /* arg2 */ 0);
- getHandler().sendMessage(msg);
- }
-
- @Override
- public IBinder asBinder() {
- // This is solely intended to be used for in-process binding.
- return null;
- }
-
- private Handler getHandler() {
- if (mHandler == null) {
- mHandler = new CallbackHandler(mHandlerThread.getLooper());
- }
- return mHandler;
- }
-
- private class CallbackHandler extends Handler {
- public CallbackHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message msg) {
- try {
- switch (msg.what) {
- case CAMERA_ERROR: {
- int errorCode = msg.arg1;
- CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
- mCallbacks.onDeviceError(errorCode, resultExtras);
- break;
- }
- case CAMERA_IDLE:
- mCallbacks.onDeviceIdle();
- break;
- case CAPTURE_STARTED: {
- long timestamp = msg.arg2 & 0xFFFFFFFFL;
- timestamp = (timestamp << 32) | (msg.arg1 & 0xFFFFFFFFL);
- CaptureResultExtras resultExtras = (CaptureResultExtras) msg.obj;
- mCallbacks.onCaptureStarted(resultExtras, timestamp);
- break;
- }
- case RESULT_RECEIVED: {
- Object[] resultArray = (Object[]) msg.obj;
- CameraMetadataNative result = (CameraMetadataNative) resultArray[0];
- CaptureResultExtras resultExtras = (CaptureResultExtras) resultArray[1];
- mCallbacks.onResultReceived(result, resultExtras,
- new PhysicalCaptureResultInfo[0]);
- break;
- }
- case PREPARED: {
- int streamId = msg.arg1;
- mCallbacks.onPrepared(streamId);
- break;
- }
- case REPEATING_REQUEST_ERROR: {
- Object[] objArray = (Object[]) msg.obj;
- long lastFrameNumber = (Long) objArray[0];
- int repeatingRequestId = (Integer) objArray[1];
- mCallbacks.onRepeatingRequestError(lastFrameNumber, repeatingRequestId);
- break;
- }
- case REQUEST_QUEUE_EMPTY: {
- mCallbacks.onRequestQueueEmpty();
- break;
- }
- default:
- throw new IllegalArgumentException(
- "Unknown callback message " + msg.what);
- }
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during camera callback " + msg.what, e);
- }
- }
- }
- }
-
- public static CameraDeviceUserShim connectBinderShim(ICameraDeviceCallbacks callbacks,
- int cameraId, Size displaySize) {
- if (DEBUG) {
- Log.d(TAG, "Opening shim Camera device");
- }
-
- /*
- * Put the camera open on a separate thread with its own looper; otherwise
- * if the main thread is used then the callbacks might never get delivered
- * (e.g. in CTS which run its own default looper only after tests)
- */
-
- CameraLooper init = new CameraLooper(cameraId);
-
- CameraCallbackThread threadCallbacks = new CameraCallbackThread(callbacks);
-
- // TODO: Make this async instead of blocking
- int initErrors = init.waitForOpen(OPEN_CAMERA_TIMEOUT_MS);
- Camera legacyCamera = init.getCamera();
-
- // Check errors old HAL initialization
- LegacyExceptionUtils.throwOnServiceError(initErrors);
-
- // Disable shutter sounds (this will work unconditionally) for api2 clients
- legacyCamera.disableShutterSound();
-
- CameraInfo info = new CameraInfo();
- Camera.getCameraInfo(cameraId, info);
-
- Camera.Parameters legacyParameters = null;
- try {
- legacyParameters = legacyCamera.getParameters();
- } catch (RuntimeException e) {
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
- "Unable to get initial parameters: " + e.getMessage());
- }
-
- CameraCharacteristics characteristics =
- LegacyMetadataMapper.createCharacteristics(legacyParameters, info, cameraId,
- displaySize);
- LegacyCameraDevice device = new LegacyCameraDevice(
- cameraId, legacyCamera, characteristics, threadCallbacks);
- return new CameraDeviceUserShim(cameraId, device, characteristics, init, threadCallbacks);
- }
-
- @Override
- public void disconnect() {
- if (DEBUG) {
- Log.d(TAG, "disconnect called.");
- }
-
- if (mLegacyDevice.isClosed()) {
- Log.w(TAG, "Cannot disconnect, device has already been closed.");
- }
-
- try {
- mLegacyDevice.close();
- } finally {
- mCameraInit.close();
- mCameraCallbacks.close();
- }
- }
-
- @Override
- public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
- if (DEBUG) {
- Log.d(TAG, "submitRequest called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot submit request, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot submit request, configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- }
- return mLegacyDevice.submitRequest(request, streaming);
- }
-
- @Override
- public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
- if (DEBUG) {
- Log.d(TAG, "submitRequestList called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot submit request list, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot submit request, configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- }
- return mLegacyDevice.submitRequestList(request, streaming);
- }
-
- @Override
- public long cancelRequest(int requestId) {
- if (DEBUG) {
- Log.d(TAG, "cancelRequest called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot cancel request, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot cancel request, configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- }
- return mLegacyDevice.cancelRequest(requestId);
- }
-
- @Override
- public boolean isSessionConfigurationSupported(SessionConfiguration sessionConfig) {
- if (sessionConfig.getSessionType() != SessionConfiguration.SESSION_REGULAR) {
- Log.e(TAG, "Session type: " + sessionConfig.getSessionType() + " is different from " +
- " regular. Legacy devices support only regular session types!");
- return false;
- }
-
- if (sessionConfig.getInputConfiguration() != null) {
- Log.e(TAG, "Input configuration present, legacy devices do not support this feature!");
- return false;
- }
-
- List<OutputConfiguration> outputConfigs = sessionConfig.getOutputConfigurations();
- if (outputConfigs.isEmpty()) {
- Log.e(TAG, "Empty output configuration list!");
- return false;
- }
-
- SparseArray<Surface> surfaces = new SparseArray<Surface>(outputConfigs.size());
- int idx = 0;
- for (OutputConfiguration outputConfig : outputConfigs) {
- List<Surface> surfaceList = outputConfig.getSurfaces();
- if (surfaceList.isEmpty() || (surfaceList.size() > 1)) {
- Log.e(TAG, "Legacy devices do not support deferred or shared surfaces!");
- return false;
- }
-
- surfaces.put(idx++, outputConfig.getSurface());
- }
-
- int ret = mLegacyDevice.configureOutputs(surfaces, /*validateSurfacesOnly*/true);
-
- return ret == LegacyExceptionUtils.NO_ERROR;
- }
-
- @Override
- public void beginConfigure() {
- if (DEBUG) {
- Log.d(TAG, "beginConfigure called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot begin configure, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot begin configure, configuration change already in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- mConfiguring = true;
- }
- }
-
- @Override
- public int[] endConfigure(int operatingMode, CameraMetadataNative sessionParams) {
- if (DEBUG) {
- Log.d(TAG, "endConfigure called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot end configure, device has been closed.";
- Log.e(TAG, err);
- synchronized(mConfigureLock) {
- mConfiguring = false;
- }
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- if (operatingMode != ICameraDeviceUser.NORMAL_MODE) {
- String err = "LEGACY devices do not support this operating mode";
- Log.e(TAG, err);
- synchronized(mConfigureLock) {
- mConfiguring = false;
- }
- throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
- }
-
- SparseArray<Surface> surfaces = null;
- synchronized(mConfigureLock) {
- if (!mConfiguring) {
- String err = "Cannot end configure, no configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- if (mSurfaces != null) {
- surfaces = mSurfaces.clone();
- }
- mConfiguring = false;
- }
- mLegacyDevice.configureOutputs(surfaces);
-
- return new int[0]; // Offline mode is not supported
- }
-
- @Override
- public void deleteStream(int streamId) {
- if (DEBUG) {
- Log.d(TAG, "deleteStream called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot delete stream, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (!mConfiguring) {
- String err = "Cannot delete stream, no configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- int index = mSurfaces.indexOfKey(streamId);
- if (index < 0) {
- String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
- }
- mSurfaces.removeAt(index);
- }
- }
-
- @Override
- public int createStream(OutputConfiguration outputConfiguration) {
- if (DEBUG) {
- Log.d(TAG, "createStream called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot create stream, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (!mConfiguring) {
- String err = "Cannot create stream, beginConfigure hasn't been called yet.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
- String err = "Cannot create stream, stream rotation is not supported.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
- }
- int id = ++mSurfaceIdCounter;
- mSurfaces.put(id, outputConfiguration.getSurface());
- return id;
- }
- }
-
- @Override
- public void finalizeOutputConfigurations(int steamId, OutputConfiguration config) {
- String err = "Finalizing output configuration is not supported on legacy devices";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
-
- @Override
- public int createInputStream(int width, int height, int format) {
- String err = "Creating input stream is not supported on legacy devices";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
-
- @Override
- public Surface getInputSurface() {
- String err = "Getting input surface is not supported on legacy devices";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
-
- @Override
- public CameraMetadataNative createDefaultRequest(int templateId) {
- if (DEBUG) {
- Log.d(TAG, "createDefaultRequest called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot create default request, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- CameraMetadataNative template;
- try {
- template =
- LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
- } catch (IllegalArgumentException e) {
- String err = "createDefaultRequest - invalid templateId specified";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
- }
-
- return template;
- }
-
- @Override
- public CameraMetadataNative getCameraInfo() {
- if (DEBUG) {
- Log.d(TAG, "getCameraInfo called.");
- }
- // TODO: implement getCameraInfo.
- Log.e(TAG, "getCameraInfo unimplemented.");
- return null;
- }
-
- @Override
- public void updateOutputConfiguration(int streamId, OutputConfiguration config) {
- // TODO: b/63912484 implement updateOutputConfiguration.
- }
-
- @Override
- public void waitUntilIdle() throws RemoteException {
- if (DEBUG) {
- Log.d(TAG, "waitUntilIdle called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot wait until idle, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot wait until idle, configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- }
- mLegacyDevice.waitUntilIdle();
- }
-
- @Override
- public long flush() {
- if (DEBUG) {
- Log.d(TAG, "flush called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot flush, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- synchronized(mConfigureLock) {
- if (mConfiguring) {
- String err = "Cannot flush, configuration change in progress.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
- }
- }
- return mLegacyDevice.flush();
- }
-
- public void prepare(int streamId) {
- if (DEBUG) {
- Log.d(TAG, "prepare called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot prepare stream, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- // LEGACY doesn't support actual prepare, just signal success right away
- mCameraCallbacks.onPrepared(streamId);
- }
-
- public void prepare2(int maxCount, int streamId) {
- // We don't support this in LEGACY mode.
- prepare(streamId);
- }
-
- public void tearDown(int streamId) {
- if (DEBUG) {
- Log.d(TAG, "tearDown called.");
- }
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot tear down stream, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- // LEGACY doesn't support actual teardown, so just a no-op
- }
-
- @Override
- public void setCameraAudioRestriction(int mode) {
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot set camera audio restriction, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- mLegacyDevice.setAudioRestriction(mode);
- }
-
- @Override
- public int getGlobalAudioRestriction() {
- if (mLegacyDevice.isClosed()) {
- String err = "Cannot set camera audio restriction, device has been closed.";
- Log.e(TAG, err);
- throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
- }
-
- return mLegacyDevice.getAudioRestriction();
- }
-
- @Override
- public ICameraOfflineSession switchToOffline(ICameraDeviceCallbacks cbs,
- int[] offlineOutputIds) {
- throw new UnsupportedOperationException("Legacy device does not support offline mode");
- }
-
- @Override
- public IBinder asBinder() {
- // This is solely intended to be used for in-process binding.
- return null;
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/CaptureCollector.java b/core/java/android/hardware/camera2/legacy/CaptureCollector.java
deleted file mode 100644
index 113927c4c4b2..000000000000
--- a/core/java/android/hardware/camera2/legacy/CaptureCollector.java
+++ /dev/null
@@ -1,673 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.legacy;
-
-import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.util.Log;
-import android.util.MutableLong;
-import android.util.Pair;
-import android.view.Surface;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * Collect timestamps and state for each {@link CaptureRequest} as it passes through
- * the Legacy camera pipeline.
- */
-public class CaptureCollector {
- private static final String TAG = "CaptureCollector";
-
- private static final boolean DEBUG = false;
-
- private static final int FLAG_RECEIVED_JPEG = 1;
- private static final int FLAG_RECEIVED_JPEG_TS = 2;
- private static final int FLAG_RECEIVED_PREVIEW = 4;
- private static final int FLAG_RECEIVED_PREVIEW_TS = 8;
- private static final int FLAG_RECEIVED_ALL_JPEG = FLAG_RECEIVED_JPEG | FLAG_RECEIVED_JPEG_TS;
- private static final int FLAG_RECEIVED_ALL_PREVIEW = FLAG_RECEIVED_PREVIEW |
- FLAG_RECEIVED_PREVIEW_TS;
-
- private static final int MAX_JPEGS_IN_FLIGHT = 1;
-
- private class CaptureHolder implements Comparable<CaptureHolder>{
- private final RequestHolder mRequest;
- private final LegacyRequest mLegacy;
- public final boolean needsJpeg;
- public final boolean needsPreview;
-
- private long mTimestamp = 0;
- private int mReceivedFlags = 0;
- private boolean mHasStarted = false;
- private boolean mFailedJpeg = false;
- private boolean mFailedPreview = false;
- private boolean mCompleted = false;
- private boolean mPreviewCompleted = false;
-
- public CaptureHolder(RequestHolder request, LegacyRequest legacyHolder) {
- mRequest = request;
- mLegacy = legacyHolder;
- needsJpeg = request.hasJpegTargets();
- needsPreview = request.hasPreviewTargets();
- }
-
- public boolean isPreviewCompleted() {
- return (mReceivedFlags & FLAG_RECEIVED_ALL_PREVIEW) == FLAG_RECEIVED_ALL_PREVIEW;
- }
-
- public boolean isJpegCompleted() {
- return (mReceivedFlags & FLAG_RECEIVED_ALL_JPEG) == FLAG_RECEIVED_ALL_JPEG;
- }
-
- public boolean isCompleted() {
- return (needsJpeg == isJpegCompleted()) && (needsPreview == isPreviewCompleted());
- }
-
- public void tryComplete() {
- if (!mPreviewCompleted && needsPreview && isPreviewCompleted()) {
- CaptureCollector.this.onPreviewCompleted();
- mPreviewCompleted = true;
- }
-
- if (isCompleted() && !mCompleted) {
- if (mFailedPreview || mFailedJpeg) {
- if (!mHasStarted) {
- // Send a request error if the capture has not yet started.
- mRequest.failRequest();
- CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_REQUEST);
- } else {
- // Send buffer dropped errors for each pending buffer if the request has
- // started.
- for (Surface targetSurface : mRequest.getRequest().getTargets() ) {
- try {
- if (mRequest.jpegType(targetSurface)) {
- if (mFailedJpeg) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.
- ERROR_CAMERA_BUFFER,
- targetSurface);
- }
- } else {
- // preview buffer
- if (mFailedPreview) {
- CaptureCollector.this.mDeviceState.setCaptureResult(mRequest,
- /*result*/null,
- CameraDeviceImpl.CameraDeviceCallbacks.
- ERROR_CAMERA_BUFFER,
- targetSurface);
- }
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.e(TAG, "Unexpected exception when querying Surface: " + e);
- }
- }
- }
- }
- CaptureCollector.this.onRequestCompleted(CaptureHolder.this);
- mCompleted = true;
- }
- }
-
- public void setJpegTimestamp(long timestamp) {
- if (DEBUG) {
- Log.d(TAG, "setJpegTimestamp - called for request " + mRequest.getRequestId());
- }
- if (!needsJpeg) {
- throw new IllegalStateException(
- "setJpegTimestamp called for capture with no jpeg targets.");
- }
- if (isCompleted()) {
- throw new IllegalStateException(
- "setJpegTimestamp called on already completed request.");
- }
-
- mReceivedFlags |= FLAG_RECEIVED_JPEG_TS;
-
- if (mTimestamp == 0) {
- mTimestamp = timestamp;
- }
-
- if (!mHasStarted) {
- mHasStarted = true;
- CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
- CameraDeviceState.NO_CAPTURE_ERROR);
- }
-
- tryComplete();
- }
-
- public void setJpegProduced() {
- if (DEBUG) {
- Log.d(TAG, "setJpegProduced - called for request " + mRequest.getRequestId());
- }
- if (!needsJpeg) {
- throw new IllegalStateException(
- "setJpegProduced called for capture with no jpeg targets.");
- }
- if (isCompleted()) {
- throw new IllegalStateException(
- "setJpegProduced called on already completed request.");
- }
-
- mReceivedFlags |= FLAG_RECEIVED_JPEG;
- tryComplete();
- }
-
- public void setJpegFailed() {
- if (DEBUG) {
- Log.d(TAG, "setJpegFailed - called for request " + mRequest.getRequestId());
- }
- if (!needsJpeg || isJpegCompleted()) {
- return;
- }
- mFailedJpeg = true;
-
- mReceivedFlags |= FLAG_RECEIVED_JPEG;
- mReceivedFlags |= FLAG_RECEIVED_JPEG_TS;
- tryComplete();
- }
-
- public void setPreviewTimestamp(long timestamp) {
- if (DEBUG) {
- Log.d(TAG, "setPreviewTimestamp - called for request " + mRequest.getRequestId());
- }
- if (!needsPreview) {
- throw new IllegalStateException(
- "setPreviewTimestamp called for capture with no preview targets.");
- }
- if (isCompleted()) {
- throw new IllegalStateException(
- "setPreviewTimestamp called on already completed request.");
- }
-
- mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS;
-
- if (mTimestamp == 0) {
- mTimestamp = timestamp;
- }
-
- if (!needsJpeg) {
- if (!mHasStarted) {
- mHasStarted = true;
- CaptureCollector.this.mDeviceState.setCaptureStart(mRequest, mTimestamp,
- CameraDeviceState.NO_CAPTURE_ERROR);
- }
- }
-
- tryComplete();
- }
-
- public void setPreviewProduced() {
- if (DEBUG) {
- Log.d(TAG, "setPreviewProduced - called for request " + mRequest.getRequestId());
- }
- if (!needsPreview) {
- throw new IllegalStateException(
- "setPreviewProduced called for capture with no preview targets.");
- }
- if (isCompleted()) {
- throw new IllegalStateException(
- "setPreviewProduced called on already completed request.");
- }
-
- mReceivedFlags |= FLAG_RECEIVED_PREVIEW;
- tryComplete();
- }
-
- public void setPreviewFailed() {
- if (DEBUG) {
- Log.d(TAG, "setPreviewFailed - called for request " + mRequest.getRequestId());
- }
- if (!needsPreview || isPreviewCompleted()) {
- return;
- }
- mFailedPreview = true;
-
- mReceivedFlags |= FLAG_RECEIVED_PREVIEW;
- mReceivedFlags |= FLAG_RECEIVED_PREVIEW_TS;
- tryComplete();
- }
-
- // Comparison and equals based on frame number.
- @Override
- public int compareTo(CaptureHolder captureHolder) {
- return (mRequest.getFrameNumber() > captureHolder.mRequest.getFrameNumber()) ? 1 :
- ((mRequest.getFrameNumber() == captureHolder.mRequest.getFrameNumber()) ? 0 :
- -1);
- }
-
- // Comparison and equals based on frame number.
- @Override
- public boolean equals(Object o) {
- return o instanceof CaptureHolder && compareTo((CaptureHolder) o) == 0;
- }
- }
-
- private final TreeSet<CaptureHolder> mActiveRequests;
- private final ArrayDeque<CaptureHolder> mJpegCaptureQueue;
- private final ArrayDeque<CaptureHolder> mJpegProduceQueue;
- private final ArrayDeque<CaptureHolder> mPreviewCaptureQueue;
- private final ArrayDeque<CaptureHolder> mPreviewProduceQueue;
- private final ArrayList<CaptureHolder> mCompletedRequests = new ArrayList<>();
-
- private final ReentrantLock mLock = new ReentrantLock();
- private final Condition mIsEmpty;
- private final Condition mPreviewsEmpty;
- private final Condition mNotFull;
- private final CameraDeviceState mDeviceState;
- private int mInFlight = 0;
- private int mInFlightPreviews = 0;
- private final int mMaxInFlight;
-
- /**
- * Create a new {@link CaptureCollector} that can modify the given {@link CameraDeviceState}.
- *
- * @param maxInFlight max allowed in-flight requests.
- * @param deviceState the {@link CameraDeviceState} to update as requests are processed.
- */
- public CaptureCollector(int maxInFlight, CameraDeviceState deviceState) {
- mMaxInFlight = maxInFlight;
- mJpegCaptureQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
- mJpegProduceQueue = new ArrayDeque<>(MAX_JPEGS_IN_FLIGHT);
- mPreviewCaptureQueue = new ArrayDeque<>(mMaxInFlight);
- mPreviewProduceQueue = new ArrayDeque<>(mMaxInFlight);
- mActiveRequests = new TreeSet<>();
- mIsEmpty = mLock.newCondition();
- mNotFull = mLock.newCondition();
- mPreviewsEmpty = mLock.newCondition();
- mDeviceState = deviceState;
- }
-
- /**
- * Queue a new request.
- *
- * <p>
- * For requests that use the Camera1 API preview output stream, this will block if there are
- * already {@code maxInFlight} requests in progress (until at least one prior request has
- * completed). For requests that use the Camera1 API jpeg callbacks, this will block until
- * all prior requests have been completed to avoid stopping preview for
- * {@link android.hardware.Camera#takePicture} before prior preview requests have been
- * completed.
- * </p>
- * @param holder the {@link RequestHolder} for this request.
- * @param legacy the {@link LegacyRequest} for this request; this will not be mutated.
- * @param timeout a timeout to use for this call.
- * @param unit the units to use for the timeout.
- * @return {@code false} if this method timed out.
- * @throws InterruptedException if this thread is interrupted.
- */
- public boolean queueRequest(RequestHolder holder, LegacyRequest legacy, long timeout,
- TimeUnit unit)
- throws InterruptedException {
- CaptureHolder h = new CaptureHolder(holder, legacy);
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- if (DEBUG) {
- Log.d(TAG, "queueRequest for request " + holder.getRequestId() +
- " - " + mInFlight + " requests remain in flight.");
- }
-
- if (!(h.needsJpeg || h.needsPreview)) {
- throw new IllegalStateException("Request must target at least one output surface!");
- }
-
- if (h.needsJpeg) {
- // Wait for all current requests to finish before queueing jpeg.
- while (mInFlight > 0) {
- if (nanos <= 0) {
- return false;
- }
- nanos = mIsEmpty.awaitNanos(nanos);
- }
- mJpegCaptureQueue.add(h);
- mJpegProduceQueue.add(h);
- }
- if (h.needsPreview) {
- while (mInFlight >= mMaxInFlight) {
- if (nanos <= 0) {
- return false;
- }
- nanos = mNotFull.awaitNanos(nanos);
- }
- mPreviewCaptureQueue.add(h);
- mPreviewProduceQueue.add(h);
- mInFlightPreviews++;
- }
- mActiveRequests.add(h);
-
- mInFlight++;
- return true;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Wait all queued requests to complete.
- *
- * @param timeout a timeout to use for this call.
- * @param unit the units to use for the timeout.
- * @return {@code false} if this method timed out.
- * @throws InterruptedException if this thread is interrupted.
- */
- public boolean waitForEmpty(long timeout, TimeUnit unit) throws InterruptedException {
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- while (mInFlight > 0) {
- if (nanos <= 0) {
- return false;
- }
- nanos = mIsEmpty.awaitNanos(nanos);
- }
- return true;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Wait all queued requests that use the Camera1 API preview output to complete.
- *
- * @param timeout a timeout to use for this call.
- * @param unit the units to use for the timeout.
- * @return {@code false} if this method timed out.
- * @throws InterruptedException if this thread is interrupted.
- */
- public boolean waitForPreviewsEmpty(long timeout, TimeUnit unit) throws InterruptedException {
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- while (mInFlightPreviews > 0) {
- if (nanos <= 0) {
- return false;
- }
- nanos = mPreviewsEmpty.awaitNanos(nanos);
- }
- return true;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Wait for the specified request to be completed (all buffers available).
- *
- * <p>May not wait for the same request more than once, since a successful wait
- * will erase the history of that request.</p>
- *
- * @param holder the {@link RequestHolder} for this request.
- * @param timeout a timeout to use for this call.
- * @param unit the units to use for the timeout.
- * @param timestamp the timestamp of the request will be written out to here, in ns
- *
- * @return {@code false} if this method timed out.
- *
- * @throws InterruptedException if this thread is interrupted.
- */
- public boolean waitForRequestCompleted(RequestHolder holder, long timeout, TimeUnit unit,
- MutableLong timestamp)
- throws InterruptedException {
- long nanos = unit.toNanos(timeout);
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- while (!removeRequestIfCompleted(holder, /*out*/timestamp)) {
- if (nanos <= 0) {
- return false;
- }
- nanos = mNotFull.awaitNanos(nanos);
- }
- return true;
- } finally {
- lock.unlock();
- }
- }
-
- private boolean removeRequestIfCompleted(RequestHolder holder, MutableLong timestamp) {
- int i = 0;
- for (CaptureHolder h : mCompletedRequests) {
- if (h.mRequest.equals(holder)) {
- timestamp.value = h.mTimestamp;
- mCompletedRequests.remove(i);
- return true;
- }
- i++;
- }
-
- return false;
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the jpeg capture has begun.
- *
- * @param timestamp the time of the jpeg capture.
- * @return the {@link RequestHolder} for the request associated with this capture.
- */
- public RequestHolder jpegCaptured(long timestamp) {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h = mJpegCaptureQueue.poll();
- if (h == null) {
- Log.w(TAG, "jpegCaptured called with no jpeg request on queue!");
- return null;
- }
- h.setJpegTimestamp(timestamp);
- return h.mRequest;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the jpeg capture has completed.
- *
- * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
- */
- public Pair<RequestHolder, Long> jpegProduced() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h = mJpegProduceQueue.poll();
- if (h == null) {
- Log.w(TAG, "jpegProduced called with no jpeg request on queue!");
- return null;
- }
- h.setJpegProduced();
- return new Pair<>(h.mRequest, h.mTimestamp);
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Check if there are any pending capture requests that use the Camera1 API preview output.
- *
- * @return {@code true} if there are pending preview requests.
- */
- public boolean hasPendingPreviewCaptures() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- return !mPreviewCaptureQueue.isEmpty();
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the preview capture has begun.
- *
- * @param timestamp the time of the preview capture.
- * @return a pair containing the {@link RequestHolder} and the timestamp of the capture.
- */
- public Pair<RequestHolder, Long> previewCaptured(long timestamp) {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h = mPreviewCaptureQueue.poll();
- if (h == null) {
- if (DEBUG) {
- Log.d(TAG, "previewCaptured called with no preview request on queue!");
- }
- return null;
- }
- h.setPreviewTimestamp(timestamp);
- return new Pair<>(h.mRequest, h.mTimestamp);
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the preview capture has completed.
- *
- * @return the {@link RequestHolder} for the request associated with this capture.
- */
- public RequestHolder previewProduced() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h = mPreviewProduceQueue.poll();
- if (h == null) {
- Log.w(TAG, "previewProduced called with no preview request on queue!");
- return null;
- }
- h.setPreviewProduced();
- return h.mRequest;
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the next pending preview capture has failed.
- */
- public void failNextPreview() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h1 = mPreviewCaptureQueue.peek();
- CaptureHolder h2 = mPreviewProduceQueue.peek();
-
- // Find the request with the lowest frame number.
- CaptureHolder h = (h1 == null) ? h2 :
- ((h2 == null) ? h1 :
- ((h1.compareTo(h2) <= 0) ? h1 :
- h2));
-
- if (h != null) {
- mPreviewCaptureQueue.remove(h);
- mPreviewProduceQueue.remove(h);
- mActiveRequests.remove(h);
- h.setPreviewFailed();
- }
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} that the next pending jpeg capture has failed.
- */
- public void failNextJpeg() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h1 = mJpegCaptureQueue.peek();
- CaptureHolder h2 = mJpegProduceQueue.peek();
-
- // Find the request with the lowest frame number.
- CaptureHolder h = (h1 == null) ? h2 :
- ((h2 == null) ? h1 :
- ((h1.compareTo(h2) <= 0) ? h1 :
- h2));
-
- if (h != null) {
- mJpegCaptureQueue.remove(h);
- mJpegProduceQueue.remove(h);
- mActiveRequests.remove(h);
- h.setJpegFailed();
- }
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Called to alert the {@link CaptureCollector} all pending captures have failed.
- */
- public void failAll() {
- final ReentrantLock lock = this.mLock;
- lock.lock();
- try {
- CaptureHolder h;
- while ((h = mActiveRequests.pollFirst()) != null) {
- h.setPreviewFailed();
- h.setJpegFailed();
- }
- mPreviewCaptureQueue.clear();
- mPreviewProduceQueue.clear();
- mJpegCaptureQueue.clear();
- mJpegProduceQueue.clear();
- } finally {
- lock.unlock();
- }
- }
-
- private void onPreviewCompleted() {
- mInFlightPreviews--;
- if (mInFlightPreviews < 0) {
- throw new IllegalStateException(
- "More preview captures completed than requests queued.");
- }
- if (mInFlightPreviews == 0) {
- mPreviewsEmpty.signalAll();
- }
- }
-
- private void onRequestCompleted(CaptureHolder capture) {
- RequestHolder request = capture.mRequest;
-
- mInFlight--;
- if (DEBUG) {
- Log.d(TAG, "Completed request " + request.getRequestId() +
- ", " + mInFlight + " requests remain in flight.");
- }
- if (mInFlight < 0) {
- throw new IllegalStateException(
- "More captures completed than requests queued.");
- }
-
- mCompletedRequests.add(capture);
- mActiveRequests.remove(capture);
-
- mNotFull.signalAll();
- if (mInFlight == 0) {
- mIsEmpty.signalAll();
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/GLThreadManager.java b/core/java/android/hardware/camera2/legacy/GLThreadManager.java
deleted file mode 100644
index 152d82d5a6da..000000000000
--- a/core/java/android/hardware/camera2/legacy/GLThreadManager.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.SurfaceTexture;
-import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Size;
-import android.view.Surface;
-
-import java.util.Collection;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * GLThreadManager handles the thread used for rendering into the configured output surfaces.
- */
-public class GLThreadManager {
- private final String TAG;
- private static final boolean DEBUG = false;
-
- private static final int MSG_NEW_CONFIGURATION = 1;
- private static final int MSG_NEW_FRAME = 2;
- private static final int MSG_CLEANUP = 3;
- private static final int MSG_DROP_FRAMES = 4;
- private static final int MSG_ALLOW_FRAMES = 5;
-
- private CaptureCollector mCaptureCollector;
-
- private final CameraDeviceState mDeviceState;
-
- private final SurfaceTextureRenderer mTextureRenderer;
-
- private final RequestHandlerThread mGLHandlerThread;
-
- private final RequestThreadManager.FpsCounter mPrevCounter =
- new RequestThreadManager.FpsCounter("GL Preview Producer");
-
- /**
- * Container object for Configure messages.
- */
- private static class ConfigureHolder {
- public final ConditionVariable condition;
- public final Collection<Pair<Surface, Size>> surfaces;
- public final CaptureCollector collector;
-
- public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface,
- Size>> surfaces, CaptureCollector collector) {
- this.condition = condition;
- this.surfaces = surfaces;
- this.collector = collector;
- }
- }
-
- private final Handler.Callback mGLHandlerCb = new Handler.Callback() {
- private boolean mCleanup = false;
- private boolean mConfigured = false;
- private boolean mDroppingFrames = false;
-
- @SuppressWarnings("unchecked")
- @Override
- public boolean handleMessage(Message msg) {
- if (mCleanup) {
- return true;
- }
- try {
- switch (msg.what) {
- case MSG_NEW_CONFIGURATION:
- ConfigureHolder configure = (ConfigureHolder) msg.obj;
- mTextureRenderer.cleanupEGLContext();
- mTextureRenderer.configureSurfaces(configure.surfaces);
- mCaptureCollector = checkNotNull(configure.collector);
- configure.condition.open();
- mConfigured = true;
- break;
- case MSG_NEW_FRAME:
- if (mDroppingFrames) {
- Log.w(TAG, "Ignoring frame.");
- break;
- }
- if (DEBUG) {
- mPrevCounter.countAndLog();
- }
- if (!mConfigured) {
- Log.e(TAG, "Dropping frame, EGL context not configured!");
- }
- mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
- break;
- case MSG_CLEANUP:
- mTextureRenderer.cleanupEGLContext();
- mCleanup = true;
- mConfigured = false;
- break;
- case MSG_DROP_FRAMES:
- mDroppingFrames = true;
- break;
- case MSG_ALLOW_FRAMES:
- mDroppingFrames = false;
- break;
- case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
- // OK: Ignore message.
- break;
- default:
- Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
- break;
- }
- } catch (Exception e) {
- Log.e(TAG, "Received exception on GL render thread: ", e);
- mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- }
- return true;
- }
- };
-
- /**
- * Create a new GL thread and renderer.
- *
- * @param cameraId the camera id for this thread.
- * @param facing direction the camera is facing.
- * @param state {@link CameraDeviceState} to use for error handling.
- */
- public GLThreadManager(int cameraId, int facing, CameraDeviceState state) {
- mTextureRenderer = new SurfaceTextureRenderer(facing);
- TAG = String.format("CameraDeviceGLThread-%d", cameraId);
- mGLHandlerThread = new RequestHandlerThread(TAG, mGLHandlerCb);
- mDeviceState = state;
- }
-
- /**
- * Start the thread.
- *
- * <p>
- * This must be called before queueing new frames.
- * </p>
- */
- public void start() {
- mGLHandlerThread.start();
- }
-
- /**
- * Wait until the thread has started.
- */
- public void waitUntilStarted() {
- mGLHandlerThread.waitUntilStarted();
- }
-
- /**
- * Quit the thread.
- *
- * <p>
- * No further methods can be called after this.
- * </p>
- */
- public void quit() {
- Handler handler = mGLHandlerThread.getHandler();
- handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
- mGLHandlerThread.quitSafely();
- try {
- mGLHandlerThread.join();
- } catch (InterruptedException e) {
- Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
- mGLHandlerThread.getName(), mGLHandlerThread.getId()));
- }
- }
-
- /**
- * Queue a new call to draw into the surfaces specified in the next available preview
- * request from the {@link CaptureCollector} passed to
- * {@link #setConfigurationAndWait(java.util.Collection, CaptureCollector)};
- */
- public void queueNewFrame() {
- Handler handler = mGLHandlerThread.getHandler();
-
- /**
- * Avoid queuing more than one new frame. If we are not consuming faster than frames
- * are produced, drop frames rather than allowing the queue to back up.
- */
- if (!handler.hasMessages(MSG_NEW_FRAME)) {
- handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME));
- } else {
- Log.e(TAG, "GLThread dropping frame. Not consuming frames quickly enough!");
- }
- }
-
- /**
- * Configure the GL renderer for the given set of output surfaces, and block until
- * this configuration has been applied.
- *
- * @param surfaces a collection of pairs of {@link android.view.Surface}s and their
- * corresponding sizes to configure.
- * @param collector a {@link CaptureCollector} to retrieve requests from.
- */
- public void setConfigurationAndWait(Collection<Pair<Surface, Size>> surfaces,
- CaptureCollector collector) {
- checkNotNull(collector, "collector must not be null");
- Handler handler = mGLHandlerThread.getHandler();
-
- final ConditionVariable condition = new ConditionVariable(/*closed*/false);
- ConfigureHolder configure = new ConfigureHolder(condition, surfaces, collector);
-
- Message m = handler.obtainMessage(MSG_NEW_CONFIGURATION, /*arg1*/0, /*arg2*/0, configure);
- handler.sendMessage(m);
-
- // Block until configuration applied.
- condition.block();
- }
-
- /**
- * Get the underlying surface to produce frames from.
- *
- * <p>
- * This returns the surface that is drawn into the set of surfaces passed in for each frame.
- * This method should only be called after a call to
- * {@link #setConfigurationAndWait(java.util.Collection)}. Calling this before the first call
- * to {@link #setConfigurationAndWait(java.util.Collection)}, after {@link #quit()}, or
- * concurrently to one of these calls may result in an invalid
- * {@link android.graphics.SurfaceTexture} being returned.
- * </p>
- *
- * @return an {@link android.graphics.SurfaceTexture} to draw to.
- */
- public SurfaceTexture getCurrentSurfaceTexture() {
- return mTextureRenderer.getSurfaceTexture();
- }
-
- /**
- * Ignore any subsequent calls to {@link #queueNewFrame(java.util.Collection)}.
- */
- public void ignoreNewFrames() {
- mGLHandlerThread.getHandler().sendEmptyMessage(MSG_DROP_FRAMES);
- }
-
- /**
- * Wait until no messages are queued.
- */
- public void waitUntilIdle() {
- mGLHandlerThread.waitUntilIdle();
- }
-
- /**
- * Re-enable drawing new frames after a call to {@link #ignoreNewFrames()}.
- */
- public void allowNewFrames() {
- mGLHandlerThread.getHandler().sendEmptyMessage(MSG_ALLOW_FRAMES);
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
deleted file mode 100644
index fdd578c419d8..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ /dev/null
@@ -1,886 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.ImageFormat;
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.impl.CaptureResultExtras;
-import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
-import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.utils.ArrayUtils;
-import android.hardware.camera2.utils.SubmitInfo;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Size;
-import android.util.SparseArray;
-import android.view.Surface;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * This class emulates the functionality of a Camera2 device using a the old Camera class.
- *
- * <p>
- * There are two main components that are used to implement this:
- * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
- * - A message-queue based pipeline that manages an old Camera class, and executes capture and
- * configuration requests.
- * </p>
- */
-public class LegacyCameraDevice implements AutoCloseable {
- private final String TAG;
-
- private static final boolean DEBUG = false;
- private final int mCameraId;
- private final CameraCharacteristics mStaticCharacteristics;
- private final ICameraDeviceCallbacks mDeviceCallbacks;
- private final CameraDeviceState mDeviceState = new CameraDeviceState();
- private SparseArray<Surface> mConfiguredSurfaces;
- private boolean mClosed = false;
-
- private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
-
- private final HandlerThread mResultThread = new HandlerThread("ResultThread");
- private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
- private final Handler mCallbackHandler;
- private final Handler mResultHandler;
- private static final int ILLEGAL_VALUE = -1;
-
- // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h
- private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000;
- private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
- private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
- private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
- private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200;
- private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
-
- public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding
-
- // Keep up to date with values in system/core/include/system/window.h
- public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
-
- private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
- return getExtrasFromRequest(holder,
- /*errorCode*/CameraDeviceState.NO_CAPTURE_ERROR, /*errorArg*/null);
- }
-
- private CaptureResultExtras getExtrasFromRequest(RequestHolder holder,
- int errorCode, Object errorArg) {
- int errorStreamId = -1;
- if (errorCode == CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_BUFFER) {
- Surface errorTarget = (Surface) errorArg;
- int indexOfTarget = mConfiguredSurfaces.indexOfValue(errorTarget);
- if (indexOfTarget < 0) {
- Log.e(TAG, "Buffer drop error reported for unknown Surface");
- } else {
- errorStreamId = mConfiguredSurfaces.keyAt(indexOfTarget);
- }
- }
- if (holder == null) {
- return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
- ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, null,
- ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
- }
- return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
- /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
- /*partialResultCount*/1, errorStreamId, null, holder.getFrameNumber(), -1, -1);
- }
-
- /**
- * Listener for the camera device state machine. Calls the appropriate
- * {@link ICameraDeviceCallbacks} for each state transition.
- */
- private final CameraDeviceState.CameraDeviceStateListener mStateListener =
- new CameraDeviceState.CameraDeviceStateListener() {
- @Override
- public void onError(final int errorCode, final Object errorArg, final RequestHolder holder) {
- if (DEBUG) {
- Log.d(TAG, "onError called, errorCode = " + errorCode + ", errorArg = " + errorArg);
- }
- switch (errorCode) {
- /*
- * Only be considered idle if we hit a fatal error
- * and no further requests can be processed.
- */
- case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
- case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
- case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
- mIdle.open();
-
- if (DEBUG) {
- Log.d(TAG, "onError - opening idle");
- }
- }
- }
-
- final CaptureResultExtras extras = getExtrasFromRequest(holder, errorCode, errorArg);
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onError callback for request " + holder.getRequestId() +
- ", with error code " + errorCode);
- }
- try {
- mDeviceCallbacks.onDeviceError(errorCode, extras);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onCameraError callback: ", e);
- }
- }
- });
- }
-
- @Override
- public void onConfiguring() {
- // Do nothing
- if (DEBUG) {
- Log.d(TAG, "doing onConfiguring callback.");
- }
- }
-
- @Override
- public void onIdle() {
- if (DEBUG) {
- Log.d(TAG, "onIdle called");
- }
-
- mIdle.open();
-
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onIdle callback.");
- }
- try {
- mDeviceCallbacks.onDeviceIdle();
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onCameraIdle callback: ", e);
- }
- }
- });
- }
-
- @Override
- public void onBusy() {
- mIdle.close();
-
- if (DEBUG) {
- Log.d(TAG, "onBusy called");
- }
- }
-
- @Override
- public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
- final CaptureResultExtras extras = getExtrasFromRequest(holder);
-
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onCaptureStarted callback for request " +
- holder.getRequestId());
- }
- try {
- mDeviceCallbacks.onCaptureStarted(extras, timestamp);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onCameraError callback: ", e);
- }
- }
- });
- }
-
- @Override
- public void onRequestQueueEmpty() {
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onRequestQueueEmpty callback");
- }
- try {
- mDeviceCallbacks.onRequestQueueEmpty();
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onRequestQueueEmpty callback: ",
- e);
- }
- }
- });
- }
-
- @Override
- public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
- final CaptureResultExtras extras = getExtrasFromRequest(holder);
-
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onCaptureResult callback for request " +
- holder.getRequestId());
- }
- try {
- mDeviceCallbacks.onResultReceived(result, extras,
- new PhysicalCaptureResultInfo[0]);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onCameraError callback: ", e);
- }
- }
- });
- }
-
- @Override
- public void onRepeatingRequestError(final long lastFrameNumber,
- final int repeatingRequestId) {
- mResultHandler.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "doing onRepeatingRequestError callback.");
- }
- try {
- mDeviceCallbacks.onRepeatingRequestError(lastFrameNumber,
- repeatingRequestId);
- } catch (RemoteException e) {
- throw new IllegalStateException(
- "Received remote exception during onRepeatingRequestError " +
- "callback: ", e);
- }
- }
- });
- }
- };
-
- private final RequestThreadManager mRequestThreadManager;
-
- /**
- * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
- * converted to this; YV12 and NV21 are the two currently supported formats.
- *
- * @param s the surface to check.
- * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
- * format.
- */
- static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
- int nativeType = detectSurfaceType(s);
- return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
- nativeType == ImageFormat.NV21;
- }
-
- /**
- * Create a new emulated camera device from a given Camera 1 API camera.
- *
- * <p>
- * The {@link Camera} provided to this constructor must already have been successfully opened,
- * and ownership of the provided camera is passed to this object. No further calls to the
- * camera methods should be made following this constructor.
- * </p>
- *
- * @param cameraId the id of the camera.
- * @param camera an open {@link Camera} device.
- * @param characteristics the static camera characteristics for this camera device
- * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
- */
- public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
- ICameraDeviceCallbacks callbacks) {
- mCameraId = cameraId;
- mDeviceCallbacks = callbacks;
- TAG = String.format("CameraDevice-%d-LE", mCameraId);
-
- mResultThread.start();
- mResultHandler = new Handler(mResultThread.getLooper());
- mCallbackHandlerThread.start();
- mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
- mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
- mStaticCharacteristics = characteristics;
- mRequestThreadManager =
- new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
- mRequestThreadManager.start();
- }
-
- /**
- * Configure the device with a set of output surfaces.
- *
- * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
- *
- * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
- *
- * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
- * list; it must not be modified by the caller once it's passed in.
- * @return an error code for this binder operation, or {@link NO_ERROR}
- * on success.
- */
- public int configureOutputs(SparseArray<Surface> outputs) {
- return configureOutputs(outputs, /*validateSurfacesOnly*/false);
- }
-
- /**
- * Configure the device with a set of output surfaces.
- *
- * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
- *
- * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
- *
- * @param outputs a list of surfaces to set. LegacyCameraDevice will take ownership of this
- * list; it must not be modified by the caller once it's passed in.
- * @param validateSurfacesOnly If set it will only check whether the outputs are supported
- * and avoid any device configuration.
- * @return an error code for this binder operation, or {@link NO_ERROR}
- * on success.
- * @hide
- */
- public int configureOutputs(SparseArray<Surface> outputs, boolean validateSurfacesOnly) {
- List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
- if (outputs != null) {
- int count = outputs.size();
- for (int i = 0; i < count; i++) {
- Surface output = outputs.valueAt(i);
- if (output == null) {
- Log.e(TAG, "configureOutputs - null outputs are not allowed");
- return BAD_VALUE;
- }
- if (!output.isValid()) {
- Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
- return BAD_VALUE;
- }
- StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
- get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-
- // Validate surface size and format.
- try {
- Size s = getSurfaceSize(output);
- int surfaceType = detectSurfaceType(output);
-
- boolean flexibleConsumer = isFlexibleConsumer(output);
-
- Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
- if (sizes == null) {
- if (surfaceType == ImageFormat.PRIVATE) {
-
- // YUV_420_888 is always present in LEGACY for all
- // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the
- // API (i.e. {@code #getOutputSizes} works here).
- sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
- } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
- sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
- }
- }
-
- if (!ArrayUtils.contains(sizes, s)) {
- if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) {
- sizedSurfaces.add(new Pair<>(output, s));
- } else {
- String reason = (sizes == null) ? "format is invalid." :
- ("size not in valid set: " + Arrays.toString(sizes));
- Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " +
- "0x%x is not valid, %s", s.getWidth(), s.getHeight(),
- surfaceType, reason));
- return BAD_VALUE;
- }
- } else {
- sizedSurfaces.add(new Pair<>(output, s));
- }
- // Lock down the size before configuration
- if (!validateSurfacesOnly) {
- setSurfaceDimens(output, s.getWidth(), s.getHeight());
- }
- } catch (BufferQueueAbandonedException e) {
- Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
- return BAD_VALUE;
- }
-
- }
- }
-
- if (validateSurfacesOnly) {
- return LegacyExceptionUtils.NO_ERROR;
- }
-
- boolean success = false;
- if (mDeviceState.setConfiguring()) {
- mRequestThreadManager.configure(sizedSurfaces);
- success = mDeviceState.setIdle();
- }
-
- if (success) {
- mConfiguredSurfaces = outputs;
- } else {
- return LegacyExceptionUtils.INVALID_OPERATION;
- }
- return LegacyExceptionUtils.NO_ERROR;
- }
-
- /**
- * Submit a burst of capture requests.
- *
- * @param requestList a list of capture requests to execute.
- * @param repeating {@code true} if this burst is repeating.
- * @return the submission info, including the new request id, and the last frame number, which
- * contains either the frame number of the last frame that will be returned for this request,
- * or the frame number of the last frame that will be returned for the current repeating
- * request if this burst is set to be repeating.
- */
- public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
- if (requestList == null || requestList.length == 0) {
- Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
- throw new ServiceSpecificException(BAD_VALUE,
- "submitRequestList - Empty/null requests are not allowed");
- }
-
- List<Long> surfaceIds;
-
- try {
- surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
- getSurfaceIds(mConfiguredSurfaces);
- } catch (BufferQueueAbandonedException e) {
- throw new ServiceSpecificException(BAD_VALUE,
- "submitRequestList - configured surface is abandoned.");
- }
-
- // Make sure that there all requests have at least 1 surface; all surfaces are non-null
- for (CaptureRequest request : requestList) {
- if (request.getTargets().isEmpty()) {
- Log.e(TAG, "submitRequestList - "
- + "Each request must have at least one Surface target");
- throw new ServiceSpecificException(BAD_VALUE,
- "submitRequestList - "
- + "Each request must have at least one Surface target");
- }
-
- for (Surface surface : request.getTargets()) {
- if (surface == null) {
- Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
- throw new ServiceSpecificException(BAD_VALUE,
- "submitRequestList - Null Surface targets are not allowed");
- } else if (mConfiguredSurfaces == null) {
- Log.e(TAG, "submitRequestList - must configure " +
- " device with valid surfaces before submitting requests");
- throw new ServiceSpecificException(INVALID_OPERATION,
- "submitRequestList - must configure " +
- " device with valid surfaces before submitting requests");
- } else if (!containsSurfaceId(surface, surfaceIds)) {
- Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
- throw new ServiceSpecificException(BAD_VALUE,
- "submitRequestList - cannot use a surface that wasn't configured");
- }
- }
- }
-
- // TODO: further validation of request here
- mIdle.close();
- return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
- }
-
- /**
- * Submit a single capture request.
- *
- * @param request the capture request to execute.
- * @param repeating {@code true} if this request is repeating.
- * @return the submission info, including the new request id, and the last frame number, which
- * contains either the frame number of the last frame that will be returned for this request,
- * or the frame number of the last frame that will be returned for the current repeating
- * request if this burst is set to be repeating.
- */
- public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
- CaptureRequest[] requestList = { request };
- return submitRequestList(requestList, repeating);
- }
-
- /**
- * Cancel the repeating request with the given request id.
- *
- * @param requestId the request id of the request to cancel.
- * @return the last frame number to be returned from the HAL for the given repeating request, or
- * {@code INVALID_FRAME} if none exists.
- */
- public long cancelRequest(int requestId) {
- return mRequestThreadManager.cancelRepeating(requestId);
- }
-
- /**
- * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
- */
- public void waitUntilIdle() {
- mIdle.block();
- }
-
- /**
- * Flush any pending requests.
- *
- * @return the last frame number.
- */
- public long flush() {
- long lastFrame = mRequestThreadManager.flush();
- waitUntilIdle();
- return lastFrame;
- }
-
- public void setAudioRestriction(int mode) {
- mRequestThreadManager.setAudioRestriction(mode);
- }
-
- public int getAudioRestriction() {
- return mRequestThreadManager.getAudioRestriction();
- }
-
- /**
- * Return {@code true} if the device has been closed.
- */
- public boolean isClosed() {
- return mClosed;
- }
-
- @Override
- public void close() {
- mRequestThreadManager.quit();
- mCallbackHandlerThread.quitSafely();
- mResultThread.quitSafely();
-
- try {
- mCallbackHandlerThread.join();
- } catch (InterruptedException e) {
- Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
- mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
- }
-
- try {
- mResultThread.join();
- } catch (InterruptedException e) {
- Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
- mResultThread.getName(), mResultThread.getId()));
- }
-
- mClosed = true;
- }
-
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
- } finally {
- super.finalize();
- }
- }
-
- static long findEuclidDistSquare(Size a, Size b) {
- long d0 = a.getWidth() - b.getWidth();
- long d1 = a.getHeight() - b.getHeight();
- return d0 * d0 + d1 * d1;
- }
-
- // Keep up to date with rounding behavior in
- // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
- static Size findClosestSize(Size size, Size[] supportedSizes) {
- if (size == null || supportedSizes == null) {
- return null;
- }
- Size bestSize = null;
- for (Size s : supportedSizes) {
- if (s.equals(size)) {
- return size;
- } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null ||
- LegacyCameraDevice.findEuclidDistSquare(size, s) <
- LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) {
- bestSize = s;
- }
- }
- return bestSize;
- }
-
- /**
- * Query the surface for its currently configured default buffer size.
- * @param surface a non-{@code null} {@code Surface}
- * @return the width and height of the surface
- *
- * @throws NullPointerException if the {@code surface} was {@code null}
- * @throws BufferQueueAbandonedException if the {@code surface} was invalid
- */
- public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
- checkNotNull(surface);
-
- int[] dimens = new int[2];
- LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
-
- return new Size(dimens[0], dimens[1]);
- }
-
- public static boolean isFlexibleConsumer(Surface output) {
- int usageFlags = detectSurfaceUsageFlags(output);
-
- // Keep up to date with allowed consumer types in
- // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
- int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT;
- int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_HW_COMPOSER;
- boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 &&
- (usageFlags & allowedFlags) != 0);
- return flexibleConsumer;
- }
-
- public static boolean isPreviewConsumer(Surface output) {
- int usageFlags = detectSurfaceUsageFlags(output);
- int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT |
- GRALLOC_USAGE_SW_READ_OFTEN;
- int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
- GRALLOC_USAGE_HW_RENDER;
- boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 &&
- (usageFlags & allowedFlags) != 0);
- int surfaceFormat = ImageFormat.UNKNOWN;
- try {
- surfaceFormat = detectSurfaceType(output);
- } catch(BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Surface was abandoned", e);
- }
-
- return previewConsumer;
- }
-
- public static boolean isVideoEncoderConsumer(Surface output) {
- int usageFlags = detectSurfaceUsageFlags(output);
- int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
- GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN;
- int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER;
- boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 &&
- (usageFlags & allowedFlags) != 0);
-
- int surfaceFormat = ImageFormat.UNKNOWN;
- try {
- surfaceFormat = detectSurfaceType(output);
- } catch(BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Surface was abandoned", e);
- }
-
- return videoEncoderConsumer;
- }
-
- /**
- * Query the surface for its currently configured usage flags
- */
- static int detectSurfaceUsageFlags(Surface surface) {
- checkNotNull(surface);
- return nativeDetectSurfaceUsageFlags(surface);
- }
-
- /**
- * Query the surface for its currently configured format
- */
- public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
- checkNotNull(surface);
- int surfaceType = nativeDetectSurfaceType(surface);
-
- // TODO: remove this override since the default format should be
- // ImageFormat.PRIVATE. b/9487482
- if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
- surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
- surfaceType = ImageFormat.PRIVATE;
- }
-
- return LegacyExceptionUtils.throwOnError(surfaceType);
- }
-
- /**
- * Query the surface for its currently configured dataspace
- */
- public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException {
- checkNotNull(surface);
- return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
- }
-
- static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
- checkNotNull(surface);
-
- LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
- }
-
- static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
- if (surface == null) return;
-
- LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
- }
-
- static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
- int height, int pixelFormat)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
- checkNotNull(pixelBuffer);
- checkArgumentPositive(width, "width must be positive.");
- checkArgumentPositive(height, "height must be positive.");
-
- LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
- pixelFormat));
- }
-
- static void setSurfaceFormat(Surface surface, int pixelFormat)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
-
- LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
- }
-
- static void setSurfaceDimens(Surface surface, int width, int height)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
- checkArgumentPositive(width, "width must be positive.");
- checkArgumentPositive(height, "height must be positive.");
-
- LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
- }
-
- public static long getSurfaceId(Surface surface) throws BufferQueueAbandonedException {
- checkNotNull(surface);
- try {
- return nativeGetSurfaceId(surface);
- } catch (IllegalArgumentException e) {
- throw new BufferQueueAbandonedException();
- }
- }
-
- static List<Long> getSurfaceIds(SparseArray<Surface> surfaces)
- throws BufferQueueAbandonedException {
- if (surfaces == null) {
- throw new NullPointerException("Null argument surfaces");
- }
- List<Long> surfaceIds = new ArrayList<>();
- int count = surfaces.size();
- for (int i = 0; i < count; i++) {
- long id = getSurfaceId(surfaces.valueAt(i));
- if (id == 0) {
- throw new IllegalStateException(
- "Configured surface had null native GraphicBufferProducer pointer!");
- }
- surfaceIds.add(id);
- }
- return surfaceIds;
- }
-
- static List<Long> getSurfaceIds(Collection<Surface> surfaces)
- throws BufferQueueAbandonedException {
- if (surfaces == null) {
- throw new NullPointerException("Null argument surfaces");
- }
- List<Long> surfaceIds = new ArrayList<>();
- for (Surface s : surfaces) {
- long id = getSurfaceId(s);
- if (id == 0) {
- throw new IllegalStateException(
- "Configured surface had null native GraphicBufferProducer pointer!");
- }
- surfaceIds.add(id);
- }
- return surfaceIds;
- }
-
- static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
- long id = 0;
- try {
- id = getSurfaceId(s);
- } catch (BufferQueueAbandonedException e) {
- // If surface is abandoned, return false.
- return false;
- }
- return ids.contains(id);
- }
-
- static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
- LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
- sensorOrientation));
- }
-
- static Size getTextureSize(SurfaceTexture surfaceTexture)
- throws BufferQueueAbandonedException {
- checkNotNull(surfaceTexture);
-
- int[] dimens = new int[2];
- LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
- /*out*/dimens));
-
- return new Size(dimens[0], dimens[1]);
- }
-
- static void setNextTimestamp(Surface surface, long timestamp)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
- LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
- }
-
- static void setScalingMode(Surface surface, int mode)
- throws BufferQueueAbandonedException {
- checkNotNull(surface);
- LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
- }
-
-
- private static native int nativeDetectSurfaceType(Surface surface);
-
- private static native int nativeDetectSurfaceDataspace(Surface surface);
-
- private static native int nativeDetectSurfaceDimens(Surface surface,
- /*out*/int[/*2*/] dimens);
-
- private static native int nativeConnectSurface(Surface surface);
-
- private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
- int height, int pixelFormat);
-
- private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
-
- private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
-
- private static native long nativeGetSurfaceId(Surface surface);
-
- private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
- int sensorOrientation);
-
- private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
- /*out*/int[/*2*/] dimens);
-
- private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
-
- private static native int nativeDetectSurfaceUsageFlags(Surface surface);
-
- private static native int nativeSetScalingMode(Surface surface, int scalingMode);
-
- private static native int nativeDisconnectSurface(Surface surface);
-
- static native int nativeGetJpegFooterSize();
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
deleted file mode 100644
index 55130c8f2839..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.ICameraService;
-import android.os.ServiceSpecificException;
-import android.util.AndroidException;
-
-import static android.system.OsConstants.*;
-
-/**
- * Utility class containing exception handling used solely by the compatibility mode shim.
- */
-public class LegacyExceptionUtils {
- private static final String TAG = "LegacyExceptionUtils";
-
- public static final int NO_ERROR = 0;
- public static final int PERMISSION_DENIED = -EPERM;
- public static final int ALREADY_EXISTS = -EEXIST;
- public static final int BAD_VALUE = -EINVAL;
- public static final int DEAD_OBJECT = -ENOSYS;
- public static final int INVALID_OPERATION = -EPIPE;
- public static final int TIMED_OUT = -ETIMEDOUT;
-
- /**
- * Checked exception thrown when a BufferQueue has been abandoned by its consumer.
- */
- public static class BufferQueueAbandonedException extends AndroidException {
- public BufferQueueAbandonedException () {}
-
- public BufferQueueAbandonedException(String name) {
- super(name);
- }
-
- public BufferQueueAbandonedException(String name, Throwable cause) {
- super(name, cause);
- }
-
- public BufferQueueAbandonedException(Exception cause) {
- super(cause);
- }
- }
-
- /**
- * Throw error codes used by legacy device methods as exceptions.
- *
- * <p>Non-negative return values are passed through, negative return values are thrown as
- * exceptions.</p>
- *
- * @param errorFlag error to throw as an exception.
- * @throws {@link BufferQueueAbandonedException} for BAD_VALUE.
- * @throws {@link UnsupportedOperationException} for an unknown negative error code.
- * @return {@code errorFlag} if the value was non-negative, throws otherwise.
- */
- public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
- if (errorFlag == NO_ERROR) {
- return NO_ERROR;
- } else if (errorFlag == BAD_VALUE) {
- throw new BufferQueueAbandonedException();
- }
-
- if (errorFlag < 0) {
- throw new UnsupportedOperationException("Unknown error " + errorFlag);
- }
- return errorFlag;
- }
-
- /**
- * Throw error codes returned by the camera service as exceptions.
- *
- * @param errorFlag error to throw as an exception.
- */
- public static void throwOnServiceError(int errorFlag) {
- int errorCode = ICameraService.ERROR_INVALID_OPERATION;
- String errorMsg;
-
- if (errorFlag >= NO_ERROR) {
- return;
- } else if (errorFlag == PERMISSION_DENIED) {
- errorCode = ICameraService.ERROR_PERMISSION_DENIED;
- errorMsg = "Lacking privileges to access camera service";
- } else if (errorFlag == ALREADY_EXISTS) {
- // This should be handled at the call site. Typically this isn't bad,
- // just means we tried to do an operation that already completed.
- return;
- } else if (errorFlag == BAD_VALUE) {
- errorCode = ICameraService.ERROR_ILLEGAL_ARGUMENT;
- errorMsg = "Bad argument passed to camera service";
- } else if (errorFlag == DEAD_OBJECT) {
- errorCode = ICameraService.ERROR_DISCONNECTED;
- errorMsg = "Camera service not available";
- } else if (errorFlag == TIMED_OUT) {
- errorCode = ICameraService.ERROR_INVALID_OPERATION;
- errorMsg = "Operation timed out in camera service";
- } else if (errorFlag == -EACCES) {
- errorCode = ICameraService.ERROR_DISABLED;
- errorMsg = "Camera disabled by policy";
- } else if (errorFlag == -EBUSY) {
- errorCode = ICameraService.ERROR_CAMERA_IN_USE;
- errorMsg = "Camera already in use";
- } else if (errorFlag == -EUSERS) {
- errorCode = ICameraService.ERROR_MAX_CAMERAS_IN_USE;
- errorMsg = "Maximum number of cameras in use";
- } else if (errorFlag == -ENODEV) {
- errorCode = ICameraService.ERROR_DISCONNECTED;
- errorMsg = "Camera device not available";
- } else if (errorFlag == -EOPNOTSUPP) {
- errorCode = ICameraService.ERROR_DEPRECATED_HAL;
- errorMsg = "Deprecated camera HAL does not support this";
- } else if (errorFlag == INVALID_OPERATION) {
- errorCode = ICameraService.ERROR_INVALID_OPERATION;
- errorMsg = "Illegal state encountered in camera service.";
- } else {
- errorCode = ICameraService.ERROR_INVALID_OPERATION;
- errorMsg = "Unknown camera device error " + errorFlag;
- }
-
- throw new ServiceSpecificException(errorCode, errorMsg);
- }
-
- private LegacyExceptionUtils() {
- throw new AssertionError();
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
deleted file mode 100644
index b3b4549426f0..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyFaceDetectMapper.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.FaceDetectionListener;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.params.Face;
-import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.util.Log;
-import android.util.Size;
-
-import com.android.internal.util.ArrayUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static android.hardware.camera2.CaptureRequest.*;
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Map legacy face detect callbacks into face detection results.
- */
-@SuppressWarnings("deprecation")
-public class LegacyFaceDetectMapper {
- private static String TAG = "LegacyFaceDetectMapper";
- private static final boolean DEBUG = false;
-
- private final Camera mCamera;
- /** Is the camera capable of face detection? */
- private final boolean mFaceDetectSupported;
- /** Is the camera is running face detection? */
- private boolean mFaceDetectEnabled = false;
- /** Did the last request say to use SCENE_MODE = FACE_PRIORITY? */
- private boolean mFaceDetectScenePriority = false;
- /** Did the last request enable the face detect mode to ON? */
- private boolean mFaceDetectReporting = false;
-
- /** Synchronize access to all fields */
- private final Object mLock = new Object();
- private Camera.Face[] mFaces;
- private Camera.Face[] mFacesPrev;
- /**
- * Instantiate a new face detect mapper.
- *
- * @param camera a non-{@code null} camera1 device
- * @param characteristics a non-{@code null} camera characteristics for that camera1
- *
- * @throws NullPointerException if any of the args were {@code null}
- */
- public LegacyFaceDetectMapper(Camera camera, CameraCharacteristics characteristics) {
- mCamera = checkNotNull(camera, "camera must not be null");
- checkNotNull(characteristics, "characteristics must not be null");
-
- mFaceDetectSupported = ArrayUtils.contains(
- characteristics.get(
- CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES),
- STATISTICS_FACE_DETECT_MODE_SIMPLE);
-
- if (!mFaceDetectSupported) {
- return;
- }
-
- mCamera.setFaceDetectionListener(new FaceDetectionListener() {
-
- @Override
- public void onFaceDetection(Camera.Face[] faces, Camera camera) {
- int lengthFaces = faces == null ? 0 : faces.length;
- synchronized (mLock) {
- if (mFaceDetectEnabled) {
- mFaces = faces;
- } else if (lengthFaces > 0) {
- // stopFaceDetectMode could race against the requests, print a debug log
- Log.d(TAG,
- "onFaceDetection - Ignored some incoming faces since" +
- "face detection was disabled");
- }
- }
-
- if (DEBUG) {
- Log.v(TAG, "onFaceDetection - read " + lengthFaces + " faces");
- }
- }
- });
- }
-
- /**
- * Process the face detect mode from the capture request into an api1 face detect toggle.
- *
- * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
- * with the request.</p>
- *
- * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
- * will have the latest faces detected as reflected by the camera1 callbacks.</p>
- *
- * <p>None of the arguments will be mutated.</p>
- *
- * @param captureRequest a non-{@code null} request
- * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
- */
- public void processFaceDetectMode(CaptureRequest captureRequest,
- Camera.Parameters parameters) {
- checkNotNull(captureRequest, "captureRequest must not be null");
-
- /*
- * statistics.faceDetectMode
- */
- int fdMode = ParamsUtils.getOrDefault(captureRequest, STATISTICS_FACE_DETECT_MODE,
- STATISTICS_FACE_DETECT_MODE_OFF);
-
- if (fdMode != STATISTICS_FACE_DETECT_MODE_OFF && !mFaceDetectSupported) {
- Log.w(TAG,
- "processFaceDetectMode - Ignoring statistics.faceDetectMode; " +
- "face detection is not available");
- return;
- }
-
- /*
- * control.sceneMode
- */
- int sceneMode = ParamsUtils.getOrDefault(captureRequest, CONTROL_SCENE_MODE,
- CONTROL_SCENE_MODE_DISABLED);
- if (sceneMode == CONTROL_SCENE_MODE_FACE_PRIORITY && !mFaceDetectSupported) {
- Log.w(TAG, "processFaceDetectMode - ignoring control.sceneMode == FACE_PRIORITY; " +
- "face detection is not available");
- return;
- }
-
- // Print some warnings out in case the values were wrong
- switch (fdMode) {
- case STATISTICS_FACE_DETECT_MODE_OFF:
- case STATISTICS_FACE_DETECT_MODE_SIMPLE:
- break;
- case STATISTICS_FACE_DETECT_MODE_FULL:
- Log.w(TAG,
- "processFaceDetectMode - statistics.faceDetectMode == FULL unsupported, " +
- "downgrading to SIMPLE");
- break;
- default:
- Log.w(TAG, "processFaceDetectMode - ignoring unknown statistics.faceDetectMode = "
- + fdMode);
- return;
- }
-
- boolean enableFaceDetect = (fdMode != STATISTICS_FACE_DETECT_MODE_OFF)
- || (sceneMode == CONTROL_SCENE_MODE_FACE_PRIORITY);
- synchronized (mLock) {
- // Enable/disable face detection if it's changed since last time
- if (enableFaceDetect != mFaceDetectEnabled) {
- if (enableFaceDetect) {
- mCamera.startFaceDetection();
-
- if (DEBUG) {
- Log.v(TAG, "processFaceDetectMode - start face detection");
- }
- } else {
- mCamera.stopFaceDetection();
-
- if (DEBUG) {
- Log.v(TAG, "processFaceDetectMode - stop face detection");
- }
-
- mFaces = null;
- }
-
- mFaceDetectEnabled = enableFaceDetect;
- mFaceDetectScenePriority = sceneMode == CONTROL_SCENE_MODE_FACE_PRIORITY;
- mFaceDetectReporting = fdMode != STATISTICS_FACE_DETECT_MODE_OFF;
- }
- }
- }
-
- /**
- * Update the {@code result} camera metadata map with the new value for the
- * {@code statistics.faces} and {@code statistics.faceDetectMode}.
- *
- * <p>Face detect callbacks are processed in the background, and each call to
- * {@link #mapResultFaces} will have the latest faces as reflected by the camera1 callbacks.</p>
- *
- * <p>If the scene mode was set to {@code FACE_PRIORITY} but face detection is disabled,
- * the camera will still run face detection in the background, but no faces will be reported
- * in the capture result.</p>
- *
- * @param result a non-{@code null} result
- * @param legacyRequest a non-{@code null} request (read-only)
- */
- public void mapResultFaces(CameraMetadataNative result, LegacyRequest legacyRequest) {
- checkNotNull(result, "result must not be null");
- checkNotNull(legacyRequest, "legacyRequest must not be null");
-
- Camera.Face[] faces, previousFaces;
- int fdMode;
- boolean fdScenePriority;
- synchronized (mLock) {
- fdMode = mFaceDetectReporting ?
- STATISTICS_FACE_DETECT_MODE_SIMPLE : STATISTICS_FACE_DETECT_MODE_OFF;
-
- if (mFaceDetectReporting) {
- faces = mFaces;
- } else {
- faces = null;
- }
-
- fdScenePriority = mFaceDetectScenePriority;
-
- previousFaces = mFacesPrev;
- mFacesPrev = faces;
- }
-
- CameraCharacteristics characteristics = legacyRequest.characteristics;
- CaptureRequest request = legacyRequest.captureRequest;
- Size previewSize = legacyRequest.previewSize;
- Camera.Parameters params = legacyRequest.parameters;
-
- Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- ZoomData zoomData = ParameterUtils.convertToLegacyZoom(activeArray,
- request.get(CaptureRequest.SCALER_CROP_REGION),
- request.get(CaptureRequest.CONTROL_ZOOM_RATIO),
- previewSize, params);
-
- List<Face> convertedFaces = new ArrayList<>();
- if (faces != null) {
- for (Camera.Face face : faces) {
- if (face != null) {
- convertedFaces.add(
- ParameterUtils.convertFaceFromLegacy(face, activeArray, zoomData));
- } else {
- Log.w(TAG, "mapResultFaces - read NULL face from camera1 device");
- }
- }
- }
-
- if (DEBUG && previousFaces != faces) { // Log only in verbose and IF the faces changed
- Log.v(TAG, "mapResultFaces - changed to " + ListUtils.listToString(convertedFaces));
- }
-
- result.set(CaptureResult.STATISTICS_FACES, convertedFaces.toArray(new Face[0]));
- result.set(CaptureResult.STATISTICS_FACE_DETECT_MODE, fdMode);
-
- // Override scene mode with FACE_PRIORITY if the request was using FACE_PRIORITY
- if (fdScenePriority) {
- result.set(CaptureResult.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_FACE_PRIORITY);
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java b/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
deleted file mode 100644
index d33c09eac85d..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyFocusStateMapper.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.Camera;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.util.Log;
-
-import java.util.Objects;
-
-import static android.hardware.camera2.CaptureRequest.*;
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Map capture request data into legacy focus state transitions.
- *
- * <p>This object will asynchronously process auto-focus changes, so no interaction
- * with it is necessary beyond reading the current state and updating with the latest trigger.</p>
- */
-@SuppressWarnings("deprecation")
-public class LegacyFocusStateMapper {
- private static String TAG = "LegacyFocusStateMapper";
- private static final boolean DEBUG = false;
-
- private final Camera mCamera;
-
- private int mAfStatePrevious = CONTROL_AF_STATE_INACTIVE;
- private String mAfModePrevious = null;
-
- /** Guard mAfRun and mAfState */
- private final Object mLock = new Object();
- /** Guard access with mLock */
- private int mAfRun = 0;
- /** Guard access with mLock */
- private int mAfState = CONTROL_AF_STATE_INACTIVE;
-
- /**
- * Instantiate a new focus state mapper.
- *
- * @param camera a non-{@code null} camera1 device
- *
- * @throws NullPointerException if any of the args were {@code null}
- */
- public LegacyFocusStateMapper(Camera camera) {
- mCamera = checkNotNull(camera, "camera must not be null");
- }
-
- /**
- * Process the AF triggers from the request as a camera1 autofocus routine.
- *
- * <p>This method should be called after the parameters are {@link LegacyRequestMapper mapped}
- * with the request.</p>
- *
- * <p>Callbacks are processed in the background, and the next call to {@link #mapResultTriggers}
- * will have the latest AF state as reflected by the camera1 callbacks.</p>
- *
- * <p>None of the arguments will be mutated.</p>
- *
- * @param captureRequest a non-{@code null} request
- * @param parameters a non-{@code null} parameters corresponding to this request (read-only)
- */
- public void processRequestTriggers(CaptureRequest captureRequest,
- Camera.Parameters parameters) {
- checkNotNull(captureRequest, "captureRequest must not be null");
-
- /*
- * control.afTrigger
- */
- int afTrigger = ParamsUtils.getOrDefault(captureRequest, CONTROL_AF_TRIGGER,
- CONTROL_AF_TRIGGER_IDLE);
-
- final String afMode = parameters.getFocusMode();
-
- if (!Objects.equals(mAfModePrevious, afMode)) {
- if (DEBUG) {
- Log.v(TAG, "processRequestTriggers - AF mode switched from " + mAfModePrevious +
- " to " + afMode);
- }
-
- // Switching modes always goes back to INACTIVE; ignore callbacks from previous modes
-
- synchronized (mLock) {
- ++mAfRun;
- mAfState = CONTROL_AF_STATE_INACTIVE;
- }
- mCamera.cancelAutoFocus();
- }
-
- mAfModePrevious = afMode;
-
- // Passive AF Scanning
- {
- final int currentAfRun;
-
- synchronized (mLock) {
- currentAfRun = mAfRun;
- }
-
- Camera.AutoFocusMoveCallback afMoveCallback = new Camera.AutoFocusMoveCallback() {
- @Override
- public void onAutoFocusMoving(boolean start, Camera camera) {
- synchronized (mLock) {
- int latestAfRun = mAfRun;
-
- if (DEBUG) {
- Log.v(TAG,
- "onAutoFocusMoving - start " + start + " latest AF run " +
- latestAfRun + ", last AF run " + currentAfRun
- );
- }
-
- if (currentAfRun != latestAfRun) {
- Log.d(TAG,
- "onAutoFocusMoving - ignoring move callbacks from old af run"
- + currentAfRun
- );
- return;
- }
-
- int newAfState = start ?
- CONTROL_AF_STATE_PASSIVE_SCAN :
- CONTROL_AF_STATE_PASSIVE_FOCUSED;
- // We never send CONTROL_AF_STATE_PASSIVE_UNFOCUSED
-
- switch (afMode) {
- case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
- case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
- break;
- // This callback should never be sent in any other AF mode
- default:
- Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
- + afMode);
-
- }
-
- mAfState = newAfState;
- }
- }
- };
-
- // Only set move callback if we can call autofocus.
- switch (afMode) {
- case Parameters.FOCUS_MODE_AUTO:
- case Parameters.FOCUS_MODE_MACRO:
- case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
- case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
- mCamera.setAutoFocusMoveCallback(afMoveCallback);
- }
- }
-
-
- // AF Locking
- switch (afTrigger) {
- case CONTROL_AF_TRIGGER_START:
-
- int afStateAfterStart;
- switch (afMode) {
- case Parameters.FOCUS_MODE_AUTO:
- case Parameters.FOCUS_MODE_MACRO:
- afStateAfterStart = CONTROL_AF_STATE_ACTIVE_SCAN;
- break;
- case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
- case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
- afStateAfterStart = CONTROL_AF_STATE_PASSIVE_SCAN;
- break;
- default:
- // EDOF, INFINITY
- afStateAfterStart = CONTROL_AF_STATE_INACTIVE;
- }
-
- final int currentAfRun;
- synchronized (mLock) {
- currentAfRun = ++mAfRun;
- mAfState = afStateAfterStart;
- }
-
- if (DEBUG) {
- Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_START, " +
- "new AF run is " + currentAfRun);
- }
-
- // Avoid calling autofocus unless we are in a state that supports calling this.
- if (afStateAfterStart == CONTROL_AF_STATE_INACTIVE) {
- break;
- }
-
- mCamera.autoFocus(new Camera.AutoFocusCallback() {
- @Override
- public void onAutoFocus(boolean success, Camera camera) {
- synchronized (mLock) {
- int latestAfRun = mAfRun;
-
- if (DEBUG) {
- Log.v(TAG, "onAutoFocus - success " + success + " latest AF run " +
- latestAfRun + ", last AF run " + currentAfRun);
- }
-
- // Ignore old auto-focus results, since another trigger was requested
- if (latestAfRun != currentAfRun) {
- Log.d(TAG, String.format("onAutoFocus - ignoring AF callback " +
- "(old run %d, new run %d)", currentAfRun, latestAfRun));
-
- return;
- }
-
- int newAfState = success ?
- CONTROL_AF_STATE_FOCUSED_LOCKED :
- CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
-
- switch (afMode) {
- case Parameters.FOCUS_MODE_AUTO:
- case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
- case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
- case Parameters.FOCUS_MODE_MACRO:
- break;
- // This callback should never be sent in any other AF mode
- default:
- Log.w(TAG, "onAutoFocus - got unexpected onAutoFocus in mode "
- + afMode);
-
- }
-
- mAfState = newAfState;
- }
- }
- });
-
- break;
- case CONTROL_AF_TRIGGER_CANCEL:
- synchronized (mLock) {
- int updatedAfRun;
-
- synchronized (mLock) {
- updatedAfRun = ++mAfRun;
- mAfState = CONTROL_AF_STATE_INACTIVE;
- }
-
- mCamera.cancelAutoFocus();
-
- if (DEBUG) {
- Log.v(TAG, "processRequestTriggers - got AF_TRIGGER_CANCEL, " +
- "new AF run is " + updatedAfRun);
- }
- }
-
- break;
- case CONTROL_AF_TRIGGER_IDLE:
- // No action necessary. The callbacks will handle transitions.
- break;
- default:
- Log.w(TAG, "processRequestTriggers - ignoring unknown control.afTrigger = "
- + afTrigger);
- }
- }
-
- /**
- * Update the {@code result} camera metadata map with the new value for the
- * {@code control.afState}.
- *
- * <p>AF callbacks are processed in the background, and each call to {@link #mapResultTriggers}
- * will have the latest AF state as reflected by the camera1 callbacks.</p>
- *
- * @param result a non-{@code null} result
- */
- public void mapResultTriggers(CameraMetadataNative result) {
- checkNotNull(result, "result must not be null");
-
- int newAfState;
- synchronized (mLock) {
- newAfState = mAfState;
- }
-
- if (DEBUG && newAfState != mAfStatePrevious) {
- Log.v(TAG, String.format("mapResultTriggers - afState changed from %s to %s",
- afStateToString(mAfStatePrevious), afStateToString(newAfState)));
- }
-
- result.set(CaptureResult.CONTROL_AF_STATE, newAfState);
-
- mAfStatePrevious = newAfState;
- }
-
- private static String afStateToString(int afState) {
- switch (afState) {
- case CONTROL_AF_STATE_ACTIVE_SCAN:
- return "ACTIVE_SCAN";
- case CONTROL_AF_STATE_FOCUSED_LOCKED:
- return "FOCUSED_LOCKED";
- case CONTROL_AF_STATE_INACTIVE:
- return "INACTIVE";
- case CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
- return "NOT_FOCUSED_LOCKED";
- case CONTROL_AF_STATE_PASSIVE_FOCUSED:
- return "PASSIVE_FOCUSED";
- case CONTROL_AF_STATE_PASSIVE_SCAN:
- return "PASSIVE_SCAN";
- case CONTROL_AF_STATE_PASSIVE_UNFOCUSED:
- return "PASSIVE_UNFOCUSED";
- default :
- return "UNKNOWN(" + afState + ")";
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
deleted file mode 100644
index 362ddfae67bf..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ /dev/null
@@ -1,1532 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.ImageFormat;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.CameraInfo;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraDevice;
-import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.MeteringRectangle;
-import android.hardware.camera2.params.StreamConfiguration;
-import android.hardware.camera2.params.StreamConfigurationDuration;
-import android.hardware.camera2.utils.ArrayUtils;
-import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.util.Log;
-import android.util.Range;
-import android.util.Size;
-import android.util.SizeF;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.CameraCharacteristics.*;
-import static android.hardware.camera2.legacy.ParameterUtils.*;
-
-/**
- * Provide legacy-specific implementations of camera2 metadata for legacy devices, such as the
- * camera characteristics.
- */
-@SuppressWarnings("deprecation")
-public class LegacyMetadataMapper {
- private static final String TAG = "LegacyMetadataMapper";
- private static final boolean DEBUG = false;
-
- private static final long NS_PER_MS = 1000000;
-
- // from graphics.h
- public static final int HAL_PIXEL_FORMAT_RGBA_8888 = PixelFormat.RGBA_8888;
- public static final int HAL_PIXEL_FORMAT_BGRA_8888 = 0x5;
- public static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
- public static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
-
- // for metadata
- private static final float LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS = 0.0f;
-
- private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW = 0; // no raw support
- private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC = 3; // preview, video, cb
- private static final int REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL = 1; // 1 jpeg only
- private static final int REQUEST_MAX_NUM_INPUT_STREAMS_COUNT = 0; // no reprocessing
-
- /** Assume 3 HAL1 stages: Exposure, Read-out, Post-Processing */
- private static final int REQUEST_PIPELINE_MAX_DEPTH_HAL1 = 3;
- /** Assume 3 shim stages: Preview input, Split output, Format conversion for output */
- private static final int REQUEST_PIPELINE_MAX_DEPTH_OURS = 3;
- /* TODO: Update above maxDepth values once we do more performance measurements */
-
- // For approximating JPEG stall durations
- private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // 200 milliseconds
- private static final long APPROXIMATE_SENSOR_AREA_PX = (1 << 23); // 8 megapixels
- private static final long APPROXIMATE_JPEG_ENCODE_TIME_MS = 600; // 600 milliseconds
-
- static final int UNKNOWN_MODE = -1;
-
- // Maximum difference between a preview size aspect ratio and a jpeg size aspect ratio
- private static final float PREVIEW_ASPECT_RATIO_TOLERANCE = 0.01f;
-
- /*
- * Development hijinks: Lie about not supporting certain capabilities
- *
- * - Unblock some CTS tests from running whose main intent is not the metadata itself
- *
- * TODO: Remove these constants and strip out any code that previously relied on them
- * being set to true.
- */
- static final boolean LIE_ABOUT_AE_STATE = false;
- static final boolean LIE_ABOUT_AE_MAX_REGIONS = false;
- static final boolean LIE_ABOUT_AF = false;
- static final boolean LIE_ABOUT_AF_MAX_REGIONS = false;
- static final boolean LIE_ABOUT_AWB_STATE = false;
- static final boolean LIE_ABOUT_AWB = false;
-
-
- /**
- * Create characteristics for a legacy device by mapping the {@code parameters}
- * and {@code info}
- *
- * @param parameters A non-{@code null} parameters set
- * @param info Camera info with camera facing direction and angle of orientation
- * @param cameraId Current camera Id
- * @param displaySize Device display size
- *
- * @return static camera characteristics for a camera device
- *
- * @throws NullPointerException if any of the args were {@code null}
- */
- public static CameraCharacteristics createCharacteristics(Camera.Parameters parameters,
- CameraInfo info, int cameraId, Size displaySize) {
- checkNotNull(parameters, "parameters must not be null");
- checkNotNull(info, "info must not be null");
-
- String paramStr = parameters.flatten();
- android.hardware.CameraInfo outerInfo = new android.hardware.CameraInfo();
- outerInfo.info = info;
-
- return createCharacteristics(paramStr, outerInfo, cameraId, displaySize);
- }
-
- /**
- * Create characteristics for a legacy device by mapping the {@code parameters}
- * and {@code info}
- *
- * @param parameters A string parseable by {@link Camera.Parameters#unflatten}
- * @param info Camera info with camera facing direction and angle of orientation
- * @param cameraId Current camera id
- * @param displaySize Device display size
- * @return static camera characteristics for a camera device
- *
- * @throws NullPointerException if any of the args were {@code null}
- */
- public static CameraCharacteristics createCharacteristics(String parameters,
- android.hardware.CameraInfo info, int cameraId, Size displaySize) {
- checkNotNull(parameters, "parameters must not be null");
- checkNotNull(info, "info must not be null");
- checkNotNull(info.info, "info.info must not be null");
-
- CameraMetadataNative m = new CameraMetadataNative();
-
- mapCharacteristicsFromInfo(m, info.info);
-
- Camera.Parameters params = Camera.getEmptyParameters();
- params.unflatten(parameters);
- mapCharacteristicsFromParameters(m, params);
-
- if (DEBUG) {
- Log.v(TAG, "createCharacteristics metadata:");
- Log.v(TAG, "--------------------------------------------------- (start)");
- m.dumpToLog();
- Log.v(TAG, "--------------------------------------------------- (end)");
- }
-
- m.setCameraId(cameraId);
- m.setDisplaySize(displaySize);
-
- return new CameraCharacteristics(m);
- }
-
- private static void mapCharacteristicsFromInfo(CameraMetadataNative m, CameraInfo i) {
- m.set(LENS_FACING, i.facing == CameraInfo.CAMERA_FACING_BACK ?
- LENS_FACING_BACK : LENS_FACING_FRONT);
- m.set(SENSOR_ORIENTATION, i.orientation);
- }
-
- private static void mapCharacteristicsFromParameters(CameraMetadataNative m,
- Camera.Parameters p) {
-
- /*
- * colorCorrection.*
- */
- m.set(COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
- new int[] { COLOR_CORRECTION_ABERRATION_MODE_FAST,
- COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY });
- /*
- * control.ae*
- */
- mapControlAe(m, p);
- /*
- * control.af*
- */
- mapControlAf(m, p);
- /*
- * control.awb*
- */
- mapControlAwb(m, p);
- /*
- * control.*
- * - Anything that doesn't have a set of related fields
- */
- mapControlOther(m, p);
- /*
- * lens.*
- */
- mapLens(m, p);
- /*
- * flash.*
- */
- mapFlash(m, p);
- /*
- * jpeg.*
- */
- mapJpeg(m, p);
-
- /*
- * noiseReduction.*
- */
- m.set(NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
- new int[] { NOISE_REDUCTION_MODE_FAST,
- NOISE_REDUCTION_MODE_HIGH_QUALITY});
-
- /*
- * scaler.*
- */
- mapScaler(m, p);
-
- /*
- * sensor.*
- */
- mapSensor(m, p);
-
- /*
- * statistics.*
- */
- mapStatistics(m, p);
-
- /*
- * sync.*
- */
- mapSync(m, p);
-
- /*
- * info.supportedHardwareLevel
- */
- m.set(INFO_SUPPORTED_HARDWARE_LEVEL, INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
-
- /*
- * scaler.availableStream*, scaler.available*Durations, sensor.info.maxFrameDuration
- */
- mapScalerStreamConfigs(m, p);
-
- // Order matters below: Put this last so that we can read the metadata set previously
-
- /*
- * request.*
- */
- mapRequest(m, p);
-
- }
-
- private static void mapScalerStreamConfigs(CameraMetadataNative m, Camera.Parameters p) {
-
- ArrayList<StreamConfiguration> availableStreamConfigs = new ArrayList<>();
- /*
- * Implementation-defined (preview, recording, etc) -> use camera1 preview sizes
- * YUV_420_888 cpu callbacks -> use camera1 preview sizes
- * Other preview callbacks (CPU) -> use camera1 preview sizes
- * JPEG still capture -> use camera1 still capture sizes
- *
- * Use platform-internal format constants here, since StreamConfigurationMap does the
- * remapping to public format constants.
- */
- List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
- List<Camera.Size> jpegSizes = p.getSupportedPictureSizes();
- /*
- * Work-around for b/17589233:
- * - Some HALs's largest preview size aspect ratio does not match the largest JPEG size AR
- * - This causes a large amount of problems with focus/metering because it's relative to
- * preview, making the difference between the JPEG and preview viewport inaccessible
- * - This boils down to metering or focusing areas being "arbitrarily" cropped
- * in the capture result.
- * - Work-around the HAL limitations by removing all of the largest preview sizes
- * until we get one with the same aspect ratio as the jpeg size.
- */
- {
- SizeAreaComparator areaComparator = new SizeAreaComparator();
-
- // Sort preview to min->max
- Collections.sort(previewSizes, areaComparator);
-
- Camera.Size maxJpegSize = SizeAreaComparator.findLargestByArea(jpegSizes);
- float jpegAspectRatio = maxJpegSize.width * 1.0f / maxJpegSize.height;
-
- if (DEBUG) {
- Log.v(TAG, String.format("mapScalerStreamConfigs - largest JPEG area %dx%d, AR=%f",
- maxJpegSize.width, maxJpegSize.height, jpegAspectRatio));
- }
-
- // Now remove preview sizes from the end (largest->smallest) until aspect ratio matches
- while (!previewSizes.isEmpty()) {
- int index = previewSizes.size() - 1; // max is always at the end
- Camera.Size size = previewSizes.get(index);
-
- float previewAspectRatio = size.width * 1.0f / size.height;
-
- if (Math.abs(jpegAspectRatio - previewAspectRatio) >=
- PREVIEW_ASPECT_RATIO_TOLERANCE) {
- previewSizes.remove(index); // Assume removing from end is O(1)
-
- if (DEBUG) {
- Log.v(TAG, String.format(
- "mapScalerStreamConfigs - removed preview size %dx%d, AR=%f "
- + "was not the same",
- size.width, size.height, previewAspectRatio));
- }
- } else {
- break;
- }
- }
-
- if (previewSizes.isEmpty()) {
- // Fall-back to the original faulty behavior, but at least work
- Log.w(TAG, "mapScalerStreamConfigs - failed to find any preview size matching " +
- "JPEG aspect ratio " + jpegAspectRatio);
- previewSizes = p.getSupportedPreviewSizes();
- }
-
- // Sort again, this time in descending order max->min
- Collections.sort(previewSizes, Collections.reverseOrder(areaComparator));
- }
-
- appendStreamConfig(availableStreamConfigs,
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, previewSizes);
- appendStreamConfig(availableStreamConfigs,
- ImageFormat.YUV_420_888, previewSizes);
- for (int format : p.getSupportedPreviewFormats()) {
- if (ImageFormat.isPublicFormat(format) && format != ImageFormat.NV21) {
- appendStreamConfig(availableStreamConfigs, format, previewSizes);
- } else if (DEBUG) {
- /*
- * Do not add any formats unknown to us
- * (since it would fail runtime checks in StreamConfigurationMap)
- */
- Log.v(TAG,
- String.format("mapStreamConfigs - Skipping format %x", format));
- }
- }
-
- appendStreamConfig(availableStreamConfigs,
- HAL_PIXEL_FORMAT_BLOB, p.getSupportedPictureSizes());
- /*
- * scaler.availableStreamConfigurations
- */
- m.set(SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
- availableStreamConfigs.toArray(new StreamConfiguration[0]));
-
- /*
- * scaler.availableMinFrameDurations
- */
- // No frame durations available
- m.set(SCALER_AVAILABLE_MIN_FRAME_DURATIONS, new StreamConfigurationDuration[0]);
-
- StreamConfigurationDuration[] jpegStalls =
- new StreamConfigurationDuration[jpegSizes.size()];
- int i = 0;
- long longestStallDuration = -1;
- for (Camera.Size s : jpegSizes) {
- long stallDuration = calculateJpegStallDuration(s);
- jpegStalls[i++] = new StreamConfigurationDuration(HAL_PIXEL_FORMAT_BLOB, s.width,
- s.height, stallDuration);
- if (longestStallDuration < stallDuration) {
- longestStallDuration = stallDuration;
- }
- }
- /*
- * scaler.availableStallDurations
- */
- // Set stall durations for jpeg, other formats use default stall duration
- m.set(SCALER_AVAILABLE_STALL_DURATIONS, jpegStalls);
-
- /*
- * sensor.info.maxFrameDuration
- */
- m.set(SENSOR_INFO_MAX_FRAME_DURATION, longestStallDuration);
- }
-
- @SuppressWarnings({"unchecked"})
- private static void mapControlAe(CameraMetadataNative m, Camera.Parameters p) {
- /*
- * control.aeAvailableAntiBandingModes
- */
- List<String> antiBandingModes = p.getSupportedAntibanding();
- if (antiBandingModes != null && antiBandingModes.size() > 0) { // antibanding is optional
- int[] modes = new int[antiBandingModes.size()];
- int j = 0;
- for (String mode : antiBandingModes) {
- int convertedMode = convertAntiBandingMode(mode);
- if (DEBUG && convertedMode == -1) {
- Log.v(TAG, "Antibanding mode " + ((mode == null) ? "NULL" : mode) +
- " not supported, skipping...");
- } else {
- modes[j++] = convertedMode;
- }
- }
- m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, Arrays.copyOf(modes, j));
- } else {
- m.set(CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, new int[0]);
- }
-
- /*
- * control.aeAvailableTargetFpsRanges
- */
- {
- List<int[]> fpsRanges = p.getSupportedPreviewFpsRange();
- if (fpsRanges == null) {
- throw new AssertionError("Supported FPS ranges cannot be null.");
- }
- int rangesSize = fpsRanges.size();
- if (rangesSize <= 0) {
- throw new AssertionError("At least one FPS range must be supported.");
- }
- Range<Integer>[] ranges = new Range[rangesSize];
- int i = 0;
- for (int[] r : fpsRanges) {
- ranges[i++] = Range.create(
- (int) Math.floor(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0),
- (int) Math.ceil(r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0));
- }
- m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges);
- }
-
- /*
- * control.aeAvailableModes
- */
- {
- List<String> flashModes = p.getSupportedFlashModes();
-
- String[] flashModeStrings = new String[] {
- Camera.Parameters.FLASH_MODE_OFF,
- Camera.Parameters.FLASH_MODE_AUTO,
- Camera.Parameters.FLASH_MODE_ON,
- Camera.Parameters.FLASH_MODE_RED_EYE,
- // Map these manually
- Camera.Parameters.FLASH_MODE_TORCH,
- };
- int[] flashModeInts = new int[] {
- CONTROL_AE_MODE_ON,
- CONTROL_AE_MODE_ON_AUTO_FLASH,
- CONTROL_AE_MODE_ON_ALWAYS_FLASH,
- CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE
- };
- int[] aeAvail = ArrayUtils.convertStringListToIntArray(
- flashModes, flashModeStrings, flashModeInts);
-
- // No flash control -> AE is always on
- if (aeAvail == null || aeAvail.length == 0) {
- aeAvail = new int[] {
- CONTROL_AE_MODE_ON
- };
- }
-
- // Note that AE_MODE_OFF is never available.
- m.set(CONTROL_AE_AVAILABLE_MODES, aeAvail);
- }
-
- /*
- * control.aeCompensationRanges
- */
- {
- int min = p.getMinExposureCompensation();
- int max = p.getMaxExposureCompensation();
-
- m.set(CONTROL_AE_COMPENSATION_RANGE, Range.create(min, max));
- }
-
- /*
- * control.aeCompensationStep
- */
- {
- float step = p.getExposureCompensationStep();
-
- m.set(CONTROL_AE_COMPENSATION_STEP, ParamsUtils.createRational(step));
- }
-
- /*
- * control.aeLockAvailable
- */
- {
- boolean aeLockAvailable = p.isAutoExposureLockSupported();
-
- m.set(CONTROL_AE_LOCK_AVAILABLE, aeLockAvailable);
- }
- }
-
-
- @SuppressWarnings({"unchecked"})
- private static void mapControlAf(CameraMetadataNative m, Camera.Parameters p) {
- /*
- * control.afAvailableModes
- */
- {
- List<String> focusModes = p.getSupportedFocusModes();
-
- String[] focusModeStrings = new String[] {
- Camera.Parameters.FOCUS_MODE_AUTO,
- Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE,
- Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO,
- Camera.Parameters.FOCUS_MODE_EDOF,
- Camera.Parameters.FOCUS_MODE_INFINITY,
- Camera.Parameters.FOCUS_MODE_MACRO,
- Camera.Parameters.FOCUS_MODE_FIXED,
- };
-
- int[] focusModeInts = new int[] {
- CONTROL_AF_MODE_AUTO,
- CONTROL_AF_MODE_CONTINUOUS_PICTURE,
- CONTROL_AF_MODE_CONTINUOUS_VIDEO,
- CONTROL_AF_MODE_EDOF,
- CONTROL_AF_MODE_OFF,
- CONTROL_AF_MODE_MACRO,
- CONTROL_AF_MODE_OFF
- };
-
- List<Integer> afAvail = ArrayUtils.convertStringListToIntList(
- focusModes, focusModeStrings, focusModeInts);
-
- // No AF modes supported? That's unpossible!
- if (afAvail == null || afAvail.size() == 0) {
- Log.w(TAG, "No AF modes supported (HAL bug); defaulting to AF_MODE_OFF only");
- afAvail = new ArrayList<Integer>(/*capacity*/1);
- afAvail.add(CONTROL_AF_MODE_OFF);
- }
-
- m.set(CONTROL_AF_AVAILABLE_MODES, ArrayUtils.toIntArray(afAvail));
-
- if (DEBUG) {
- Log.v(TAG, "mapControlAf - control.afAvailableModes set to " +
- ListUtils.listToString(afAvail));
- }
- }
- }
-
- private static void mapControlAwb(CameraMetadataNative m, Camera.Parameters p) {
- /*
- * control.awbAvailableModes
- */
-
- {
- List<String> wbModes = p.getSupportedWhiteBalance();
-
- String[] wbModeStrings = new String[] {
- Camera.Parameters.WHITE_BALANCE_AUTO ,
- Camera.Parameters.WHITE_BALANCE_INCANDESCENT ,
- Camera.Parameters.WHITE_BALANCE_FLUORESCENT ,
- Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT ,
- Camera.Parameters.WHITE_BALANCE_DAYLIGHT ,
- Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT ,
- Camera.Parameters.WHITE_BALANCE_TWILIGHT ,
- Camera.Parameters.WHITE_BALANCE_SHADE ,
- };
-
- int[] wbModeInts = new int[] {
- CONTROL_AWB_MODE_AUTO,
- CONTROL_AWB_MODE_INCANDESCENT ,
- CONTROL_AWB_MODE_FLUORESCENT ,
- CONTROL_AWB_MODE_WARM_FLUORESCENT ,
- CONTROL_AWB_MODE_DAYLIGHT ,
- CONTROL_AWB_MODE_CLOUDY_DAYLIGHT ,
- CONTROL_AWB_MODE_TWILIGHT ,
- CONTROL_AWB_MODE_SHADE ,
- // Note that CONTROL_AWB_MODE_OFF is unsupported
- };
-
- List<Integer> awbAvail = ArrayUtils.convertStringListToIntList(
- wbModes, wbModeStrings, wbModeInts);
-
- // No AWB modes supported? That's unpossible!
- if (awbAvail == null || awbAvail.size() == 0) {
- Log.w(TAG, "No AWB modes supported (HAL bug); defaulting to AWB_MODE_AUTO only");
- awbAvail = new ArrayList<Integer>(/*capacity*/1);
- awbAvail.add(CONTROL_AWB_MODE_AUTO);
- }
-
- m.set(CONTROL_AWB_AVAILABLE_MODES, ArrayUtils.toIntArray(awbAvail));
-
- if (DEBUG) {
- Log.v(TAG, "mapControlAwb - control.awbAvailableModes set to " +
- ListUtils.listToString(awbAvail));
- }
-
-
- /*
- * control.awbLockAvailable
- */
- {
- boolean awbLockAvailable = p.isAutoWhiteBalanceLockSupported();
-
- m.set(CONTROL_AWB_LOCK_AVAILABLE, awbLockAvailable);
- }
- }
- }
-
- private static void mapControlOther(CameraMetadataNative m, Camera.Parameters p) {
- /*
- * android.control.availableVideoStabilizationModes
- */
- {
- int stabModes[] = p.isVideoStabilizationSupported() ?
- new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF,
- CONTROL_VIDEO_STABILIZATION_MODE_ON } :
- new int[] { CONTROL_VIDEO_STABILIZATION_MODE_OFF };
-
- m.set(CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, stabModes);
- }
-
- /*
- * android.control.maxRegions
- */
- final int AE = 0, AWB = 1, AF = 2;
-
- int[] maxRegions = new int[3];
- maxRegions[AE] = p.getMaxNumMeteringAreas();
- maxRegions[AWB] = 0; // AWB regions not supported in API1
- maxRegions[AF] = p.getMaxNumFocusAreas();
-
- if (LIE_ABOUT_AE_MAX_REGIONS) {
- maxRegions[AE] = 0;
- }
- if (LIE_ABOUT_AF_MAX_REGIONS) {
- maxRegions[AF] = 0;
- }
-
- m.set(CONTROL_MAX_REGIONS, maxRegions);
-
- /*
- * android.control.availableEffects
- */
- List<String> effectModes = p.getSupportedColorEffects();
- int[] supportedEffectModes = (effectModes == null) ? new int[0] :
- ArrayUtils.convertStringListToIntArray(effectModes, sLegacyEffectMode,
- sEffectModes);
- m.set(CONTROL_AVAILABLE_EFFECTS, supportedEffectModes);
-
- /*
- * android.control.availableSceneModes
- */
- int maxNumDetectedFaces = p.getMaxNumDetectedFaces();
- List<String> sceneModes = p.getSupportedSceneModes();
- List<Integer> supportedSceneModes =
- ArrayUtils.convertStringListToIntList(sceneModes, sLegacySceneModes, sSceneModes);
-
- // Special case where the only scene mode listed is AUTO => no scene mode
- if (sceneModes != null && sceneModes.size() == 1 &&
- sceneModes.get(0).equals(Parameters.SCENE_MODE_AUTO)) {
- supportedSceneModes = null;
- }
-
- boolean sceneModeSupported = true;
- if (supportedSceneModes == null && maxNumDetectedFaces == 0) {
- sceneModeSupported = false;
- }
-
- if (sceneModeSupported) {
- if (supportedSceneModes == null) {
- supportedSceneModes = new ArrayList<Integer>();
- }
- if (maxNumDetectedFaces > 0) { // always supports FACE_PRIORITY when face detecting
- supportedSceneModes.add(CONTROL_SCENE_MODE_FACE_PRIORITY);
- }
- // Remove all DISABLED occurrences
- if (supportedSceneModes.contains(CONTROL_SCENE_MODE_DISABLED)) {
- while(supportedSceneModes.remove(new Integer(CONTROL_SCENE_MODE_DISABLED))) {}
- }
- m.set(CONTROL_AVAILABLE_SCENE_MODES, ArrayUtils.toIntArray(supportedSceneModes));
- } else {
- m.set(CONTROL_AVAILABLE_SCENE_MODES, new int[] {CONTROL_SCENE_MODE_DISABLED});
- }
-
- /*
- * android.control.availableModes
- */
- m.set(CONTROL_AVAILABLE_MODES, sceneModeSupported ?
- new int[] { CONTROL_MODE_AUTO, CONTROL_MODE_USE_SCENE_MODE } :
- new int[] { CONTROL_MODE_AUTO });
- }
-
- private static void mapLens(CameraMetadataNative m, Camera.Parameters p) {
- /*
- * We can tell if the lens is fixed focus;
- * but if it's not, we can't tell the minimum focus distance, so leave it null then.
- */
- if (DEBUG) {
- Log.v(TAG, "mapLens - focus-mode='" + p.getFocusMode() + "'");
- }
-
- if (Camera.Parameters.FOCUS_MODE_FIXED.equals(p.getFocusMode())) {
- /*
- * lens.info.minimumFocusDistance
- */
- m.set(LENS_INFO_MINIMUM_FOCUS_DISTANCE, LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS);
-
- if (DEBUG) {
- Log.v(TAG, "mapLens - lens.info.minimumFocusDistance = 0");
- }
- } else {
- if (DEBUG) {
- Log.v(TAG, "mapLens - lens.info.minimumFocusDistance is unknown");
- }
- }
-
- float[] focalLengths = new float[] { p.getFocalLength() };
- m.set(LENS_INFO_AVAILABLE_FOCAL_LENGTHS, focalLengths);
- }
-
- private static void mapFlash(CameraMetadataNative m, Camera.Parameters p) {
- boolean flashAvailable = false;
- List<String> supportedFlashModes = p.getSupportedFlashModes();
-
- if (supportedFlashModes != null) {
- // If only 'OFF' is available, we don't really have flash support
- flashAvailable = !ListUtils.listElementsEqualTo(
- supportedFlashModes, Camera.Parameters.FLASH_MODE_OFF);
- }
-
- /*
- * flash.info.available
- */
- m.set(FLASH_INFO_AVAILABLE, flashAvailable);
- }
-
- private static void mapJpeg(CameraMetadataNative m, Camera.Parameters p) {
- List<Camera.Size> thumbnailSizes = p.getSupportedJpegThumbnailSizes();
-
- if (thumbnailSizes != null) {
- Size[] sizes = convertSizeListToArray(thumbnailSizes);
- Arrays.sort(sizes, new android.hardware.camera2.utils.SizeAreaComparator());
- m.set(JPEG_AVAILABLE_THUMBNAIL_SIZES, sizes);
- }
- }
-
- private static void mapRequest(CameraMetadataNative m, Parameters p) {
- /*
- * request.availableCapabilities
- */
- int[] capabilities = { REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE };
- m.set(REQUEST_AVAILABLE_CAPABILITIES, capabilities);
-
- /*
- * request.availableCharacteristicsKeys
- */
- {
- // TODO: check if the underlying key is supported before listing a key as available
-
- // Note: We only list public keys. Native HALs should list ALL keys regardless of visibility.
-
- Key<?> availableKeys[] = new Key<?>[] {
- CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES ,
- CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES ,
- CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES ,
- CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES ,
- CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE ,
- CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP ,
- CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE ,
- CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES ,
- CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS ,
- CameraCharacteristics.CONTROL_AVAILABLE_MODES ,
- CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES ,
- CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES ,
- CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES ,
- CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE ,
- CameraCharacteristics.CONTROL_MAX_REGIONS ,
- CameraCharacteristics.CONTROL_ZOOM_RATIO_RANGE ,
- CameraCharacteristics.FLASH_INFO_AVAILABLE ,
- CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL ,
- CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES ,
- CameraCharacteristics.LENS_FACING ,
- CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS ,
- CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES ,
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES ,
- CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS ,
- CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT ,
- CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH ,
- CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM ,
-// CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP ,
- CameraCharacteristics.SCALER_CROPPING_TYPE ,
- CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES ,
- CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE ,
- CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE ,
- CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE ,
- CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE ,
- CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE ,
- CameraCharacteristics.SENSOR_ORIENTATION ,
- CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES ,
- CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT ,
- CameraCharacteristics.SYNC_MAX_LATENCY ,
- };
- List<Key<?>> characteristicsKeys = new ArrayList<>(Arrays.asList(availableKeys));
-
- /*
- * Add the conditional keys
- */
- if (m.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE) != null) {
- characteristicsKeys.add(LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- }
-
- m.set(REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
- getTagsForKeys(characteristicsKeys.toArray(new Key<?>[0])));
- }
-
- /*
- * request.availableRequestKeys
- */
- {
- CaptureRequest.Key<?> defaultAvailableKeys[] = new CaptureRequest.Key<?>[] {
- CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
- CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
- CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
- CaptureRequest.CONTROL_AE_LOCK,
- CaptureRequest.CONTROL_AE_MODE,
- CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
- CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_TRIGGER,
- CaptureRequest.CONTROL_AWB_LOCK,
- CaptureRequest.CONTROL_AWB_MODE,
- CaptureRequest.CONTROL_CAPTURE_INTENT,
- CaptureRequest.CONTROL_EFFECT_MODE,
- CaptureRequest.CONTROL_MODE,
- CaptureRequest.CONTROL_SCENE_MODE,
- CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
- CaptureRequest.CONTROL_ZOOM_RATIO,
- CaptureRequest.FLASH_MODE,
- CaptureRequest.JPEG_GPS_COORDINATES,
- CaptureRequest.JPEG_GPS_PROCESSING_METHOD,
- CaptureRequest.JPEG_GPS_TIMESTAMP,
- CaptureRequest.JPEG_ORIENTATION,
- CaptureRequest.JPEG_QUALITY,
- CaptureRequest.JPEG_THUMBNAIL_QUALITY,
- CaptureRequest.JPEG_THUMBNAIL_SIZE,
- CaptureRequest.LENS_FOCAL_LENGTH,
- CaptureRequest.NOISE_REDUCTION_MODE,
- CaptureRequest.SCALER_CROP_REGION,
- CaptureRequest.STATISTICS_FACE_DETECT_MODE,
- };
- ArrayList<CaptureRequest.Key<?>> availableKeys =
- new ArrayList<CaptureRequest.Key<?>>(Arrays.asList(defaultAvailableKeys));
-
- if (p.getMaxNumMeteringAreas() > 0) {
- availableKeys.add(CaptureRequest.CONTROL_AE_REGIONS);
- }
- if (p.getMaxNumFocusAreas() > 0) {
- availableKeys.add(CaptureRequest.CONTROL_AF_REGIONS);
- }
-
- CaptureRequest.Key<?> availableRequestKeys[] =
- new CaptureRequest.Key<?>[availableKeys.size()];
- availableKeys.toArray(availableRequestKeys);
- m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableRequestKeys));
- }
-
- /*
- * request.availableResultKeys
- */
- {
- CaptureResult.Key<?> defaultAvailableKeys[] = new CaptureResult.Key<?>[] {
- CaptureResult.COLOR_CORRECTION_ABERRATION_MODE ,
- CaptureResult.CONTROL_AE_ANTIBANDING_MODE ,
- CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION ,
- CaptureResult.CONTROL_AE_LOCK ,
- CaptureResult.CONTROL_AE_MODE ,
- CaptureResult.CONTROL_AF_MODE ,
- CaptureResult.CONTROL_AF_STATE ,
- CaptureResult.CONTROL_AWB_MODE ,
- CaptureResult.CONTROL_AWB_LOCK ,
- CaptureResult.CONTROL_MODE ,
- CaptureResult.CONTROL_ZOOM_RATIO ,
- CaptureResult.FLASH_MODE ,
- CaptureResult.JPEG_GPS_COORDINATES ,
- CaptureResult.JPEG_GPS_PROCESSING_METHOD ,
- CaptureResult.JPEG_GPS_TIMESTAMP ,
- CaptureResult.JPEG_ORIENTATION ,
- CaptureResult.JPEG_QUALITY ,
- CaptureResult.JPEG_THUMBNAIL_QUALITY ,
- CaptureResult.LENS_FOCAL_LENGTH ,
- CaptureResult.NOISE_REDUCTION_MODE ,
- CaptureResult.REQUEST_PIPELINE_DEPTH ,
- CaptureResult.SCALER_CROP_REGION ,
- CaptureResult.SENSOR_TIMESTAMP ,
- CaptureResult.STATISTICS_FACE_DETECT_MODE ,
-// CaptureResult.STATISTICS_FACES ,
- };
- List<CaptureResult.Key<?>> availableKeys =
- new ArrayList<CaptureResult.Key<?>>(Arrays.asList(defaultAvailableKeys));
-
- if (p.getMaxNumMeteringAreas() > 0) {
- availableKeys.add(CaptureResult.CONTROL_AE_REGIONS);
- }
- if (p.getMaxNumFocusAreas() > 0) {
- availableKeys.add(CaptureResult.CONTROL_AF_REGIONS);
- }
-
- CaptureResult.Key<?> availableResultKeys[] =
- new CaptureResult.Key<?>[availableKeys.size()];
- availableKeys.toArray(availableResultKeys);
- m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableResultKeys));
- }
-
- /*
- * request.maxNumOutputStreams
- */
- int[] outputStreams = {
- /* RAW */
- REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_RAW,
- /* Processed & Not-Stalling */
- REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC,
- /* Processed & Stalling */
- REQUEST_MAX_NUM_OUTPUT_STREAMS_COUNT_PROC_STALL,
- };
- m.set(REQUEST_MAX_NUM_OUTPUT_STREAMS, outputStreams);
-
- /*
- * request.maxNumInputStreams
- */
- m.set(REQUEST_MAX_NUM_INPUT_STREAMS, REQUEST_MAX_NUM_INPUT_STREAMS_COUNT);
-
- /*
- * request.partialResultCount
- */
- m.set(REQUEST_PARTIAL_RESULT_COUNT, 1); // No partial results supported
-
- /*
- * request.pipelineMaxDepth
- */
- m.set(REQUEST_PIPELINE_MAX_DEPTH,
- (byte)(REQUEST_PIPELINE_MAX_DEPTH_HAL1 + REQUEST_PIPELINE_MAX_DEPTH_OURS));
- }
-
- private static void mapScaler(CameraMetadataNative m, Parameters p) {
- /*
- * control.zoomRatioRange
- */
- Range<Float> zoomRatioRange = new Range<Float>(1.0f, ParameterUtils.getMaxZoomRatio(p));
- m.set(CONTROL_ZOOM_RATIO_RANGE, zoomRatioRange);
-
- /*
- * scaler.availableMaxDigitalZoom
- */
- m.set(SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, ParameterUtils.getMaxZoomRatio(p));
-
- /*
- * scaler.croppingType = CENTER_ONLY
- */
- m.set(SCALER_CROPPING_TYPE, SCALER_CROPPING_TYPE_CENTER_ONLY);
- }
-
- private static void mapSensor(CameraMetadataNative m, Parameters p) {
- // Use the largest jpeg size (by area) for both active array and pixel array
- Size largestJpegSize = getLargestSupportedJpegSizeByArea(p);
- /*
- * sensor.info.activeArraySize, and preCorrectionActiveArraySize
- */
- {
- Rect activeArrayRect = ParamsUtils.createRect(largestJpegSize);
- m.set(SENSOR_INFO_ACTIVE_ARRAY_SIZE, activeArrayRect);
- m.set(SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, activeArrayRect);
- }
-
- /*
- * sensor.availableTestPatternModes
- */
- {
- // Only "OFF" test pattern mode is available
- m.set(SENSOR_AVAILABLE_TEST_PATTERN_MODES, new int[] { SENSOR_TEST_PATTERN_MODE_OFF });
- }
-
- /*
- * sensor.info.pixelArraySize
- */
- m.set(SENSOR_INFO_PIXEL_ARRAY_SIZE, largestJpegSize);
-
- /*
- * sensor.info.physicalSize
- */
- {
- /*
- * Assume focal length is at infinity focus and that the lens is rectilinear.
- */
- float focalLength = p.getFocalLength(); // in mm
- double angleHor = p.getHorizontalViewAngle() * Math.PI / 180; // to radians
- double angleVer = p.getVerticalViewAngle() * Math.PI / 180; // to radians
-
- float height = (float)Math.abs(2 * focalLength * Math.tan(angleVer / 2));
- float width = (float)Math.abs(2 * focalLength * Math.tan(angleHor / 2));
-
- m.set(SENSOR_INFO_PHYSICAL_SIZE, new SizeF(width, height)); // in mm
- }
-
- /*
- * sensor.info.timestampSource
- */
- {
- m.set(SENSOR_INFO_TIMESTAMP_SOURCE, SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN);
- }
- }
-
- private static void mapStatistics(CameraMetadataNative m, Parameters p) {
- /*
- * statistics.info.availableFaceDetectModes
- */
- int[] fdModes;
-
- if (p.getMaxNumDetectedFaces() > 0) {
- fdModes = new int[] {
- STATISTICS_FACE_DETECT_MODE_OFF,
- STATISTICS_FACE_DETECT_MODE_SIMPLE
- // FULL is never-listed, since we have no way to query it statically
- };
- } else {
- fdModes = new int[] {
- STATISTICS_FACE_DETECT_MODE_OFF
- };
- }
- m.set(STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, fdModes);
-
- /*
- * statistics.info.maxFaceCount
- */
- m.set(STATISTICS_INFO_MAX_FACE_COUNT, p.getMaxNumDetectedFaces());
- }
-
- private static void mapSync(CameraMetadataNative m, Parameters p) {
- /*
- * sync.maxLatency
- */
- m.set(SYNC_MAX_LATENCY, SYNC_MAX_LATENCY_UNKNOWN);
- }
-
- private static void appendStreamConfig(
- ArrayList<StreamConfiguration> configs, int format, List<Camera.Size> sizes) {
- for (Camera.Size size : sizes) {
- StreamConfiguration config =
- new StreamConfiguration(format, size.width, size.height, /*input*/false);
- configs.add(config);
- }
- }
-
- private final static String[] sLegacySceneModes = {
- Parameters.SCENE_MODE_AUTO,
- Parameters.SCENE_MODE_ACTION,
- Parameters.SCENE_MODE_PORTRAIT,
- Parameters.SCENE_MODE_LANDSCAPE,
- Parameters.SCENE_MODE_NIGHT,
- Parameters.SCENE_MODE_NIGHT_PORTRAIT,
- Parameters.SCENE_MODE_THEATRE,
- Parameters.SCENE_MODE_BEACH,
- Parameters.SCENE_MODE_SNOW,
- Parameters.SCENE_MODE_SUNSET,
- Parameters.SCENE_MODE_STEADYPHOTO,
- Parameters.SCENE_MODE_FIREWORKS,
- Parameters.SCENE_MODE_SPORTS,
- Parameters.SCENE_MODE_PARTY,
- Parameters.SCENE_MODE_CANDLELIGHT,
- Parameters.SCENE_MODE_BARCODE,
- Parameters.SCENE_MODE_HDR,
- };
-
- private final static int[] sSceneModes = {
- CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED,
- CameraCharacteristics.CONTROL_SCENE_MODE_ACTION,
- CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT,
- CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE,
- CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT,
- CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT,
- CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE,
- CameraCharacteristics.CONTROL_SCENE_MODE_BEACH,
- CameraCharacteristics.CONTROL_SCENE_MODE_SNOW,
- CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET,
- CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO,
- CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS,
- CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS,
- CameraCharacteristics.CONTROL_SCENE_MODE_PARTY,
- CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT,
- CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE,
- CameraCharacteristics.CONTROL_SCENE_MODE_HDR,
- };
-
- static int convertSceneModeFromLegacy(String mode) {
- if (mode == null) {
- return CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED;
- }
- int index = ArrayUtils.getArrayIndex(sLegacySceneModes, mode);
- if (index < 0) {
- return UNKNOWN_MODE;
- }
- return sSceneModes[index];
- }
-
- static String convertSceneModeToLegacy(int mode) {
- if (mode == CONTROL_SCENE_MODE_FACE_PRIORITY) {
- // OK: Let LegacyFaceDetectMapper handle turning face detection on/off
- return Parameters.SCENE_MODE_AUTO;
- }
-
- int index = ArrayUtils.getArrayIndex(sSceneModes, mode);
- if (index < 0) {
- return null;
- }
- return sLegacySceneModes[index];
- }
-
- private final static String[] sLegacyEffectMode = {
- Parameters.EFFECT_NONE,
- Parameters.EFFECT_MONO,
- Parameters.EFFECT_NEGATIVE,
- Parameters.EFFECT_SOLARIZE,
- Parameters.EFFECT_SEPIA,
- Parameters.EFFECT_POSTERIZE,
- Parameters.EFFECT_WHITEBOARD,
- Parameters.EFFECT_BLACKBOARD,
- Parameters.EFFECT_AQUA,
- };
-
- private final static int[] sEffectModes = {
- CameraCharacteristics.CONTROL_EFFECT_MODE_OFF,
- CameraCharacteristics.CONTROL_EFFECT_MODE_MONO,
- CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE,
- CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE,
- CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA,
- CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE,
- CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD,
- CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD,
- CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA,
- };
-
- static int convertEffectModeFromLegacy(String mode) {
- if (mode == null) {
- return CameraCharacteristics.CONTROL_EFFECT_MODE_OFF;
- }
- int index = ArrayUtils.getArrayIndex(sLegacyEffectMode, mode);
- if (index < 0) {
- return UNKNOWN_MODE;
- }
- return sEffectModes[index];
- }
-
- static String convertEffectModeToLegacy(int mode) {
- int index = ArrayUtils.getArrayIndex(sEffectModes, mode);
- if (index < 0) {
- return null;
- }
- return sLegacyEffectMode[index];
- }
-
- /**
- * Convert the ae antibanding mode from api1 into api2.
- *
- * @param mode the api1 mode, {@code null} is allowed and will return {@code -1}.
- *
- * @return The api2 value, or {@code -1} by default if conversion failed
- */
- private static int convertAntiBandingMode(String mode) {
- if (mode == null) {
- return -1;
- }
-
- switch (mode) {
- case Camera.Parameters.ANTIBANDING_OFF: {
- return CONTROL_AE_ANTIBANDING_MODE_OFF;
- }
- case Camera.Parameters.ANTIBANDING_50HZ: {
- return CONTROL_AE_ANTIBANDING_MODE_50HZ;
- }
- case Camera.Parameters.ANTIBANDING_60HZ: {
- return CONTROL_AE_ANTIBANDING_MODE_60HZ;
- }
- case Camera.Parameters.ANTIBANDING_AUTO: {
- return CONTROL_AE_ANTIBANDING_MODE_AUTO;
- }
- default: {
- Log.w(TAG, "convertAntiBandingMode - Unknown antibanding mode " + mode);
- return -1;
- }
- }
- }
-
- /**
- * Convert the ae antibanding mode from api1 into api2.
- *
- * @param mode the api1 mode, {@code null} is allowed and will return {@code MODE_OFF}.
- *
- * @return The api2 value, or {@code MODE_OFF} by default if conversion failed
- */
- static int convertAntiBandingModeOrDefault(String mode) {
- int antiBandingMode = convertAntiBandingMode(mode);
- if (antiBandingMode == -1) {
- return CONTROL_AE_ANTIBANDING_MODE_OFF;
- }
-
- return antiBandingMode;
- }
-
- private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
- int[] legacyFps = new int[2];
- legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
- legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
- return legacyFps;
- }
-
- /**
- * Return the stall duration for a given output jpeg size in nanoseconds.
- *
- * <p>An 8mp image is chosen to have a stall duration of 0.8 seconds.</p>
- */
- private static long calculateJpegStallDuration(Camera.Size size) {
- long baseDuration = APPROXIMATE_CAPTURE_DELAY_MS * NS_PER_MS; // 200ms for capture
- long area = size.width * (long) size.height;
- long stallPerArea = APPROXIMATE_JPEG_ENCODE_TIME_MS * NS_PER_MS /
- APPROXIMATE_SENSOR_AREA_PX; // 600ms stall for 8mp
- return baseDuration + area * stallPerArea;
- }
-
- /**
- * Set the legacy parameters using the {@link LegacyRequest legacy request}.
- *
- * <p>The legacy request's parameters are changed as a side effect of calling this
- * method.</p>
- *
- * @param request a non-{@code null} legacy request
- */
- public static void convertRequestMetadata(LegacyRequest request) {
- LegacyRequestMapper.convertRequestMetadata(request);
- }
-
- private static final int[] sAllowedTemplates = {
- CameraDevice.TEMPLATE_PREVIEW,
- CameraDevice.TEMPLATE_STILL_CAPTURE,
- CameraDevice.TEMPLATE_RECORD,
- // Disallowed templates in legacy mode:
- // CameraDevice.TEMPLATE_VIDEO_SNAPSHOT,
- // CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG,
- // CameraDevice.TEMPLATE_MANUAL
- };
-
- /**
- * Create a request template
- *
- * @param c a non-{@code null} camera characteristics for this camera
- * @param templateId a non-negative template ID
- *
- * @return a non-{@code null} request template
- *
- * @throws IllegalArgumentException if {@code templateId} was invalid
- *
- * @see android.hardware.camera2.CameraDevice#TEMPLATE_MANUAL
- */
- public static CameraMetadataNative createRequestTemplate(
- CameraCharacteristics c, int templateId) {
- if (!ArrayUtils.contains(sAllowedTemplates, templateId)) {
- throw new IllegalArgumentException("templateId out of range");
- }
-
- CameraMetadataNative m = new CameraMetadataNative();
-
- /*
- * NOTE: If adding new code here and it needs to query the static info,
- * query the camera characteristics, so we can reuse this for api2 code later
- * to create our own templates in the framework
- */
-
- /*
- * control.*
- */
-
- // control.awbMode
- m.set(CaptureRequest.CONTROL_AWB_MODE, CameraMetadata.CONTROL_AWB_MODE_AUTO);
- // AWB is always unconditionally available in API1 devices
-
- // control.aeAntibandingMode
- m.set(CaptureRequest.CONTROL_AE_ANTIBANDING_MODE, CONTROL_AE_ANTIBANDING_MODE_AUTO);
-
- // control.aeExposureCompensation
- m.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
-
- // control.aeLock
- m.set(CaptureRequest.CONTROL_AE_LOCK, false);
-
- // control.aePrecaptureTrigger
- m.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
-
- // control.afTrigger
- m.set(CaptureRequest.CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
-
- // control.awbMode
- m.set(CaptureRequest.CONTROL_AWB_MODE, CONTROL_AWB_MODE_AUTO);
-
- // control.awbLock
- m.set(CaptureRequest.CONTROL_AWB_LOCK, false);
-
- // control.aeRegions, control.awbRegions, control.afRegions
- {
- Rect activeArray = c.get(SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- MeteringRectangle[] activeRegions = new MeteringRectangle[] {
- new MeteringRectangle(/*x*/0, /*y*/0, /*width*/activeArray.width() - 1,
- /*height*/activeArray.height() - 1,/*weight*/0)};
- m.set(CaptureRequest.CONTROL_AE_REGIONS, activeRegions);
- m.set(CaptureRequest.CONTROL_AWB_REGIONS, activeRegions);
- m.set(CaptureRequest.CONTROL_AF_REGIONS, activeRegions);
- }
-
- // control.captureIntent
- {
- int captureIntent;
- switch (templateId) {
- case CameraDevice.TEMPLATE_PREVIEW:
- captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
- break;
- case CameraDevice.TEMPLATE_STILL_CAPTURE:
- captureIntent = CONTROL_CAPTURE_INTENT_STILL_CAPTURE;
- break;
- case CameraDevice.TEMPLATE_RECORD:
- captureIntent = CONTROL_CAPTURE_INTENT_VIDEO_RECORD;
- break;
- default:
- // Can't get anything else since it's guarded by the IAE check
- throw new AssertionError("Impossible; keep in sync with sAllowedTemplates");
- }
- m.set(CaptureRequest.CONTROL_CAPTURE_INTENT, captureIntent);
- }
-
- // control.aeMode
- m.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
- // AE is always unconditionally available in API1 devices
-
- // control.mode
- m.set(CaptureRequest.CONTROL_MODE, CONTROL_MODE_AUTO);
-
- // control.afMode
- {
- Float minimumFocusDistance = c.get(LENS_INFO_MINIMUM_FOCUS_DISTANCE);
-
- int afMode;
- if (minimumFocusDistance != null &&
- minimumFocusDistance == LENS_INFO_MINIMUM_FOCUS_DISTANCE_FIXED_FOCUS) {
- // Cannot control auto-focus with fixed-focus cameras
- afMode = CameraMetadata.CONTROL_AF_MODE_OFF;
- } else {
- // If a minimum focus distance is reported; the camera must have AF
- afMode = CameraMetadata.CONTROL_AF_MODE_AUTO;
-
- if (templateId == CameraDevice.TEMPLATE_RECORD ||
- templateId == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
- if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
- CONTROL_AF_MODE_CONTINUOUS_VIDEO)) {
- afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO;
- }
- } else if (templateId == CameraDevice.TEMPLATE_PREVIEW ||
- templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) {
- if (ArrayUtils.contains(c.get(CONTROL_AF_AVAILABLE_MODES),
- CONTROL_AF_MODE_CONTINUOUS_PICTURE)) {
- afMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
- }
- }
- }
-
- if (DEBUG) {
- Log.v(TAG, "createRequestTemplate (templateId=" + templateId + ")," +
- " afMode=" + afMode + ", minimumFocusDistance=" + minimumFocusDistance);
- }
-
- m.set(CaptureRequest.CONTROL_AF_MODE, afMode);
- }
-
- {
- // control.aeTargetFpsRange
- Range<Integer>[] availableFpsRange = c.
- get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
-
- // Pick FPS range with highest max value, tiebreak on higher min value
- Range<Integer> bestRange = availableFpsRange[0];
- for (Range<Integer> r : availableFpsRange) {
- if (bestRange.getUpper() < r.getUpper()) {
- bestRange = r;
- } else if (bestRange.getUpper() == r.getUpper() &&
- bestRange.getLower() < r.getLower()) {
- bestRange = r;
- }
- }
- m.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, bestRange);
- }
-
- // control.sceneMode -- DISABLED is always available
- m.set(CaptureRequest.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED);
-
- // control.zoomRatio -- 1.0
- m.set(CaptureRequest.CONTROL_ZOOM_RATIO, 1.0f);
-
- /*
- * statistics.*
- */
-
- // statistics.faceDetectMode
- m.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, STATISTICS_FACE_DETECT_MODE_OFF);
-
- /*
- * flash.*
- */
-
- // flash.mode
- m.set(CaptureRequest.FLASH_MODE, FLASH_MODE_OFF);
-
- /*
- * noiseReduction.*
- */
- if (templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) {
- m.set(CaptureRequest.NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_HIGH_QUALITY);
- } else {
- m.set(CaptureRequest.NOISE_REDUCTION_MODE, NOISE_REDUCTION_MODE_FAST);
- }
-
- /*
- * colorCorrection.*
- */
- if (templateId == CameraDevice.TEMPLATE_STILL_CAPTURE) {
- m.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
- COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
- } else {
- m.set(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE,
- COLOR_CORRECTION_ABERRATION_MODE_FAST);
- }
-
- /*
- * lens.*
- */
-
- // lens.focalLength
- m.set(CaptureRequest.LENS_FOCAL_LENGTH,
- c.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0]);
-
- /*
- * jpeg.*
- */
-
- // jpeg.thumbnailSize - set smallest non-zero size if possible
- Size[] sizes = c.get(CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES);
- m.set(CaptureRequest.JPEG_THUMBNAIL_SIZE, (sizes.length > 1) ? sizes[1] : sizes[0]);
-
- // TODO: map other request template values
- return m;
- }
-
- private static int[] getTagsForKeys(Key<?>[] keys) {
- int[] tags = new int[keys.length];
-
- for (int i = 0; i < keys.length; ++i) {
- tags[i] = keys[i].getNativeKey().getTag();
- }
-
- return tags;
- }
-
- private static int[] getTagsForKeys(CaptureRequest.Key<?>[] keys) {
- int[] tags = new int[keys.length];
-
- for (int i = 0; i < keys.length; ++i) {
- tags[i] = keys[i].getNativeKey().getTag();
- }
-
- return tags;
- }
-
- private static int[] getTagsForKeys(CaptureResult.Key<?>[] keys) {
- int[] tags = new int[keys.length];
-
- for (int i = 0; i < keys.length; ++i) {
- tags[i] = keys[i].getNativeKey().getTag();
- }
-
- return tags;
- }
-
- /**
- * Convert the requested AF mode into its equivalent supported parameter.
- *
- * @param mode {@code CONTROL_AF_MODE}
- * @param supportedFocusModes list of camera1's supported focus modes
- * @return the stringified af mode, or {@code null} if its not supported
- */
- static String convertAfModeToLegacy(int mode, List<String> supportedFocusModes) {
- if (supportedFocusModes == null || supportedFocusModes.isEmpty()) {
- Log.w(TAG, "No focus modes supported; API1 bug");
- return null;
- }
-
- String param = null;
- switch (mode) {
- case CONTROL_AF_MODE_AUTO:
- param = Parameters.FOCUS_MODE_AUTO;
- break;
- case CONTROL_AF_MODE_CONTINUOUS_PICTURE:
- param = Parameters.FOCUS_MODE_CONTINUOUS_PICTURE;
- break;
- case CONTROL_AF_MODE_CONTINUOUS_VIDEO:
- param = Parameters.FOCUS_MODE_CONTINUOUS_VIDEO;
- break;
- case CONTROL_AF_MODE_EDOF:
- param = Parameters.FOCUS_MODE_EDOF;
- break;
- case CONTROL_AF_MODE_MACRO:
- param = Parameters.FOCUS_MODE_MACRO;
- break;
- case CONTROL_AF_MODE_OFF:
- if (supportedFocusModes.contains(Parameters.FOCUS_MODE_FIXED)) {
- param = Parameters.FOCUS_MODE_FIXED;
- } else {
- param = Parameters.FOCUS_MODE_INFINITY;
- }
- }
-
- if (!supportedFocusModes.contains(param)) {
- // Weed out bad user input by setting to the first arbitrary focus mode
- String defaultMode = supportedFocusModes.get(0);
- Log.w(TAG,
- String.format(
- "convertAfModeToLegacy - ignoring unsupported mode %d, " +
- "defaulting to %s", mode, defaultMode));
- param = defaultMode;
- }
-
- return param;
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequest.java b/core/java/android/hardware/camera2/legacy/LegacyRequest.java
deleted file mode 100644
index f13ac5c881e0..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyRequest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.Camera;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.util.Size;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Hold important data necessary to build the camera1 parameters up from a capture request.
- */
-public class LegacyRequest {
- /** Immutable characteristics for the camera corresponding to this request */
- public final CameraCharacteristics characteristics;
- /** Immutable capture request, as requested by the user */
- public final CaptureRequest captureRequest;
- /** Immutable api1 preview buffer size at the time of the request */
- public final Size previewSize;
- /** <em>Mutable</em> camera parameters */
- public final Camera.Parameters parameters;
-
- /**
- * Create a new legacy request; the parameters are copied.
- *
- * @param characteristics immutable static camera characteristics for this camera
- * @param captureRequest immutable user-defined capture request
- * @param previewSize immutable internal preview size used for {@link Camera#setPreviewSurface}
- * @param parameters the initial camera1 parameter state; (copied) can be mutated
- */
- public LegacyRequest(CameraCharacteristics characteristics, CaptureRequest captureRequest,
- Size previewSize, Camera.Parameters parameters) {
- this.characteristics = checkNotNull(characteristics, "characteristics must not be null");
- this.captureRequest = checkNotNull(captureRequest, "captureRequest must not be null");
- this.previewSize = checkNotNull(previewSize, "previewSize must not be null");
- checkNotNull(parameters, "parameters must not be null");
-
- this.parameters = Camera.getParametersCopy(parameters);
- }
-
- /**
- * Update the current parameters in-place to be a copy of the new parameters.
- *
- * @param parameters non-{@code null} parameters for api1 camera
- */
- public void setParameters(Camera.Parameters parameters) {
- checkNotNull(parameters, "parameters must not be null");
-
- this.parameters.copyFrom(parameters);
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
deleted file mode 100644
index 3a46379477e9..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.params.MeteringRectangle;
-import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.location.Location;
-import android.util.Log;
-import android.util.Range;
-import android.util.Size;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-import static android.hardware.camera2.CaptureRequest.*;
-
-/**
- * Provide legacy-specific implementations of camera2 CaptureRequest for legacy devices.
- */
-@SuppressWarnings("deprecation")
-public class LegacyRequestMapper {
- private static final String TAG = "LegacyRequestMapper";
- private static final boolean DEBUG = false;
-
- /** Default quality for android.jpeg.quality, android.jpeg.thumbnailQuality */
- private static final byte DEFAULT_JPEG_QUALITY = 85;
-
- /**
- * Set the legacy parameters using the {@link LegacyRequest legacy request}.
- *
- * <p>The legacy request's parameters are changed as a side effect of calling this
- * method.</p>
- *
- * @param legacyRequest a non-{@code null} legacy request
- */
- public static void convertRequestMetadata(LegacyRequest legacyRequest) {
- CameraCharacteristics characteristics = legacyRequest.characteristics;
- CaptureRequest request = legacyRequest.captureRequest;
- Size previewSize = legacyRequest.previewSize;
- Camera.Parameters params = legacyRequest.parameters;
-
- Rect activeArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
- /*
- * scaler.cropRegion
- */
- ParameterUtils.ZoomData zoomData;
- {
- zoomData = ParameterUtils.convertToLegacyZoom(activeArray,
- request.get(SCALER_CROP_REGION),
- request.get(CONTROL_ZOOM_RATIO),
- previewSize,
- params);
-
- if (params.isZoomSupported()) {
- params.setZoom(zoomData.zoomIndex);
- } else if (DEBUG) {
- Log.v(TAG, "convertRequestToMetadata - zoom is not supported");
- }
- }
-
- /*
- * colorCorrection.*
- */
- // colorCorrection.aberrationMode
- {
- int aberrationMode = ParamsUtils.getOrDefault(request,
- COLOR_CORRECTION_ABERRATION_MODE,
- /*defaultValue*/COLOR_CORRECTION_ABERRATION_MODE_FAST);
-
- if (aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_FAST &&
- aberrationMode != COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY) {
- Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
- "colorCorrection.aberrationMode = " + aberrationMode);
- }
- }
-
- /*
- * control.ae*
- */
- // control.aeAntibandingMode
- {
- String legacyMode;
- Integer antiBandingMode = request.get(CONTROL_AE_ANTIBANDING_MODE);
- if (antiBandingMode != null) {
- legacyMode = convertAeAntiBandingModeToLegacy(antiBandingMode);
- } else {
- legacyMode = ListUtils.listSelectFirstFrom(params.getSupportedAntibanding(),
- new String[] {
- Parameters.ANTIBANDING_AUTO,
- Parameters.ANTIBANDING_OFF,
- Parameters.ANTIBANDING_50HZ,
- Parameters.ANTIBANDING_60HZ,
- });
- }
-
- if (legacyMode != null) {
- params.setAntibanding(legacyMode);
- }
- }
-
- /*
- * control.aeRegions, afRegions
- */
- {
- // aeRegions
- {
- // Use aeRegions if available, fall back to using awbRegions if present
- MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
- if (request.get(CONTROL_AWB_REGIONS) != null) {
- Log.w(TAG, "convertRequestMetadata - control.awbRegions setting is not " +
- "supported, ignoring value");
- }
- int maxNumMeteringAreas = params.getMaxNumMeteringAreas();
- List<Camera.Area> meteringAreaList = convertMeteringRegionsToLegacy(
- activeArray, zoomData, aeRegions, maxNumMeteringAreas,
- /*regionName*/"AE");
-
- // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
- if (maxNumMeteringAreas > 0) {
- params.setMeteringAreas(meteringAreaList);
- }
- }
-
- // afRegions
- {
- MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
- int maxNumFocusAreas = params.getMaxNumFocusAreas();
- List<Camera.Area> focusAreaList = convertMeteringRegionsToLegacy(
- activeArray, zoomData, afRegions, maxNumFocusAreas,
- /*regionName*/"AF");
-
- // WAR: for b/17252693, some devices can't handle params.setFocusAreas(null).
- if (maxNumFocusAreas > 0) {
- params.setFocusAreas(focusAreaList);
- }
- }
- }
-
- // control.aeTargetFpsRange
- Range<Integer> aeFpsRange = request.get(CONTROL_AE_TARGET_FPS_RANGE);
- if (aeFpsRange != null) {
- int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
-
- int[] rangeToApply = null;
- for(int[] range : params.getSupportedPreviewFpsRange()) {
- // Round range up/down to integer FPS value
- int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000;
- int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000;
- if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) {
- rangeToApply = range;
- break;
- }
- }
- if (rangeToApply != null) {
- params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
- } else {
- Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
- }
- }
-
- /*
- * control
- */
-
- // control.aeExposureCompensation
- {
- Range<Integer> compensationRange =
- characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE);
- int compensation = ParamsUtils.getOrDefault(request,
- CONTROL_AE_EXPOSURE_COMPENSATION,
- /*defaultValue*/0);
-
- if (!compensationRange.contains(compensation)) {
- Log.w(TAG,
- "convertRequestMetadata - control.aeExposureCompensation " +
- "is out of range, ignoring value");
- compensation = 0;
- }
-
- params.setExposureCompensation(compensation);
- }
-
- // control.aeLock
- {
- Boolean aeLock = getIfSupported(request, CONTROL_AE_LOCK, /*defaultValue*/false,
- params.isAutoExposureLockSupported(),
- /*allowedValue*/false);
-
- if (aeLock != null) {
- params.setAutoExposureLock(aeLock);
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertRequestToMetadata - control.aeLock set to " + aeLock);
- }
-
- // TODO: Don't add control.aeLock to availableRequestKeys if it's not supported
- }
-
- // control.aeMode, flash.mode
- mapAeAndFlashMode(request, /*out*/params);
-
- // control.afMode
- {
- int afMode = ParamsUtils.getOrDefault(request, CONTROL_AF_MODE,
- /*defaultValue*/CONTROL_AF_MODE_OFF);
- String focusMode = LegacyMetadataMapper.convertAfModeToLegacy(afMode,
- params.getSupportedFocusModes());
-
- if (focusMode != null) {
- params.setFocusMode(focusMode);
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertRequestToMetadata - control.afMode "
- + afMode + " mapped to " + focusMode);
- }
- }
-
- // control.awbMode
- {
- Integer awbMode = getIfSupported(request, CONTROL_AWB_MODE,
- /*defaultValue*/CONTROL_AWB_MODE_AUTO,
- params.getSupportedWhiteBalance() != null,
- /*allowedValue*/CONTROL_AWB_MODE_AUTO);
-
- String whiteBalanceMode = null;
- if (awbMode != null) { // null iff AWB is not supported by camera1 api
- whiteBalanceMode = convertAwbModeToLegacy(awbMode);
- params.setWhiteBalance(whiteBalanceMode);
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertRequestToMetadata - control.awbMode "
- + awbMode + " mapped to " + whiteBalanceMode);
- }
- }
-
- // control.awbLock
- {
- Boolean awbLock = getIfSupported(request, CONTROL_AWB_LOCK, /*defaultValue*/false,
- params.isAutoWhiteBalanceLockSupported(),
- /*allowedValue*/false);
-
- if (awbLock != null) {
- params.setAutoWhiteBalanceLock(awbLock);
- }
-
- // TODO: Don't add control.awbLock to availableRequestKeys if it's not supported
- }
-
- // control.captureIntent
- {
- int captureIntent = ParamsUtils.getOrDefault(request,
- CONTROL_CAPTURE_INTENT,
- /*defaultValue*/CONTROL_CAPTURE_INTENT_PREVIEW);
-
- captureIntent = filterSupportedCaptureIntent(captureIntent);
-
- params.setRecordingHint(
- captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_RECORD ||
- captureIntent == CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
- }
-
- // control.videoStabilizationMode
- {
- Integer stabMode = getIfSupported(request, CONTROL_VIDEO_STABILIZATION_MODE,
- /*defaultValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF,
- params.isVideoStabilizationSupported(),
- /*allowedValue*/CONTROL_VIDEO_STABILIZATION_MODE_OFF);
-
- if (stabMode != null) {
- params.setVideoStabilization(stabMode == CONTROL_VIDEO_STABILIZATION_MODE_ON);
- }
- }
-
- // lens.focusDistance
- {
- boolean infinityFocusSupported =
- ListUtils.listContains(params.getSupportedFocusModes(),
- Parameters.FOCUS_MODE_INFINITY);
- Float focusDistance = getIfSupported(request, LENS_FOCUS_DISTANCE,
- /*defaultValue*/0f, infinityFocusSupported, /*allowedValue*/0f);
-
- if (focusDistance == null || focusDistance != 0f) {
- Log.w(TAG,
- "convertRequestToMetadata - Ignoring android.lens.focusDistance "
- + infinityFocusSupported + ", only 0.0f is supported");
- }
- }
-
- // control.sceneMode, control.mode
- {
- // TODO: Map FACE_PRIORITY scene mode to face detection.
-
- if (params.getSupportedSceneModes() != null) {
- int controlMode = ParamsUtils.getOrDefault(request, CONTROL_MODE,
- /*defaultValue*/CONTROL_MODE_AUTO);
- String modeToSet;
- switch (controlMode) {
- case CONTROL_MODE_USE_SCENE_MODE: {
- int sceneMode = ParamsUtils.getOrDefault(request, CONTROL_SCENE_MODE,
- /*defaultValue*/CONTROL_SCENE_MODE_DISABLED);
- String legacySceneMode = LegacyMetadataMapper.
- convertSceneModeToLegacy(sceneMode);
- if (legacySceneMode != null) {
- modeToSet = legacySceneMode;
- } else {
- modeToSet = Parameters.SCENE_MODE_AUTO;
- Log.w(TAG, "Skipping unknown requested scene mode: " + sceneMode);
- }
- break;
- }
- case CONTROL_MODE_AUTO: {
- modeToSet = Parameters.SCENE_MODE_AUTO;
- break;
- }
- default: {
- Log.w(TAG, "Control mode " + controlMode +
- " is unsupported, defaulting to AUTO");
- modeToSet = Parameters.SCENE_MODE_AUTO;
- }
- }
- params.setSceneMode(modeToSet);
- }
- }
-
- // control.effectMode
- {
- if (params.getSupportedColorEffects() != null) {
- int effectMode = ParamsUtils.getOrDefault(request, CONTROL_EFFECT_MODE,
- /*defaultValue*/CONTROL_EFFECT_MODE_OFF);
- String legacyEffectMode = LegacyMetadataMapper.convertEffectModeToLegacy(effectMode);
- if (legacyEffectMode != null) {
- params.setColorEffect(legacyEffectMode);
- } else {
- params.setColorEffect(Parameters.EFFECT_NONE);
- Log.w(TAG, "Skipping unknown requested effect mode: " + effectMode);
- }
- }
- }
-
- /*
- * sensor
- */
-
- // sensor.testPattern
- {
- int testPatternMode = ParamsUtils.getOrDefault(request, SENSOR_TEST_PATTERN_MODE,
- /*defaultValue*/SENSOR_TEST_PATTERN_MODE_OFF);
- if (testPatternMode != SENSOR_TEST_PATTERN_MODE_OFF) {
- Log.w(TAG, "convertRequestToMetadata - ignoring sensor.testPatternMode "
- + testPatternMode + "; only OFF is supported");
- }
- }
-
- /*
- * jpeg.*
- */
-
- // jpeg.gpsLocation
- {
- Location location = request.get(JPEG_GPS_LOCATION);
- if (location != null) {
- if (checkForCompleteGpsData(location)) {
- params.setGpsAltitude(location.getAltitude());
- params.setGpsLatitude(location.getLatitude());
- params.setGpsLongitude(location.getLongitude());
- params.setGpsProcessingMethod(location.getProvider().toUpperCase());
- params.setGpsTimestamp(location.getTime());
- } else {
- Log.w(TAG, "Incomplete GPS parameters provided in location " + location);
- }
- } else {
- params.removeGpsData();
- }
- }
-
- // jpeg.orientation
- {
- Integer orientation = request.get(CaptureRequest.JPEG_ORIENTATION);
- params.setRotation(ParamsUtils.getOrDefault(request, JPEG_ORIENTATION,
- (orientation == null) ? 0 : orientation));
- }
-
- // jpeg.quality
- {
- params.setJpegQuality(0xFF & ParamsUtils.getOrDefault(request, JPEG_QUALITY,
- DEFAULT_JPEG_QUALITY));
- }
-
- // jpeg.thumbnailQuality
- {
- params.setJpegThumbnailQuality(0xFF & ParamsUtils.getOrDefault(request,
- JPEG_THUMBNAIL_QUALITY, DEFAULT_JPEG_QUALITY));
- }
-
- // jpeg.thumbnailSize
- {
- List<Camera.Size> sizes = params.getSupportedJpegThumbnailSizes();
-
- if (sizes != null && sizes.size() > 0) {
- Size s = request.get(JPEG_THUMBNAIL_SIZE);
- boolean invalidSize = (s == null) ? false : !ParameterUtils.containsSize(sizes,
- s.getWidth(), s.getHeight());
- if (invalidSize) {
- Log.w(TAG, "Invalid JPEG thumbnail size set " + s + ", skipping thumbnail...");
- }
- if (s == null || invalidSize) {
- // (0,0) = "no thumbnail" in Camera API 1
- params.setJpegThumbnailSize(/*width*/0, /*height*/0);
- } else {
- params.setJpegThumbnailSize(s.getWidth(), s.getHeight());
- }
- }
- }
-
- /*
- * noiseReduction.*
- */
- // noiseReduction.mode
- {
- int mode = ParamsUtils.getOrDefault(request,
- NOISE_REDUCTION_MODE,
- /*defaultValue*/NOISE_REDUCTION_MODE_FAST);
-
- if (mode != NOISE_REDUCTION_MODE_FAST &&
- mode != NOISE_REDUCTION_MODE_HIGH_QUALITY) {
- Log.w(TAG, "convertRequestToMetadata - Ignoring unsupported " +
- "noiseReduction.mode = " + mode);
- }
- }
- }
-
- private static boolean checkForCompleteGpsData(Location location) {
- return location != null && location.getProvider() != null && location.getTime() != 0;
- }
-
- static int filterSupportedCaptureIntent(int captureIntent) {
- switch (captureIntent) {
- case CONTROL_CAPTURE_INTENT_CUSTOM:
- case CONTROL_CAPTURE_INTENT_PREVIEW:
- case CONTROL_CAPTURE_INTENT_STILL_CAPTURE:
- case CONTROL_CAPTURE_INTENT_VIDEO_RECORD:
- case CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT:
- break;
- case CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG:
- case CONTROL_CAPTURE_INTENT_MANUAL:
- captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
- Log.w(TAG, "Unsupported control.captureIntent value " + captureIntent
- + "; default to PREVIEW");
- default:
- captureIntent = CONTROL_CAPTURE_INTENT_PREVIEW;
- Log.w(TAG, "Unknown control.captureIntent value " + captureIntent
- + "; default to PREVIEW");
- }
-
- return captureIntent;
- }
-
- private static List<Camera.Area> convertMeteringRegionsToLegacy(
- Rect activeArray, ParameterUtils.ZoomData zoomData,
- MeteringRectangle[] meteringRegions, int maxNumMeteringAreas, String regionName) {
- if (meteringRegions == null || maxNumMeteringAreas <= 0) {
- if (maxNumMeteringAreas > 0) {
- return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
- } else {
- return null;
- }
- }
-
- // Add all non-zero weight regions to the list
- List<MeteringRectangle> meteringRectangleList = new ArrayList<>();
- for (MeteringRectangle rect : meteringRegions) {
- if (rect.getMeteringWeight() != MeteringRectangle.METERING_WEIGHT_DONT_CARE) {
- meteringRectangleList.add(rect);
- }
- }
-
- if (meteringRectangleList.size() == 0) {
- Log.w(TAG, "Only received metering rectangles with weight 0.");
- return Arrays.asList(ParameterUtils.CAMERA_AREA_DEFAULT);
- }
-
- // Ignore any regions beyond our maximum supported count
- int countMeteringAreas =
- Math.min(maxNumMeteringAreas, meteringRectangleList.size());
- List<Camera.Area> meteringAreaList = new ArrayList<>(countMeteringAreas);
-
- for (int i = 0; i < countMeteringAreas; ++i) {
- MeteringRectangle rect = meteringRectangleList.get(i);
-
- ParameterUtils.MeteringData meteringData =
- ParameterUtils.convertMeteringRectangleToLegacy(activeArray, rect, zoomData);
- meteringAreaList.add(meteringData.meteringArea);
- }
-
- if (maxNumMeteringAreas < meteringRectangleList.size()) {
- Log.w(TAG,
- "convertMeteringRegionsToLegacy - Too many requested " + regionName +
- " regions, ignoring all beyond the first " + maxNumMeteringAreas);
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertMeteringRegionsToLegacy - " + regionName + " areas = "
- + ParameterUtils.stringFromAreaList(meteringAreaList));
- }
-
- return meteringAreaList;
- }
-
- private static void mapAeAndFlashMode(CaptureRequest r, /*out*/Parameters p) {
- int flashMode = ParamsUtils.getOrDefault(r, FLASH_MODE, FLASH_MODE_OFF);
- int aeMode = ParamsUtils.getOrDefault(r, CONTROL_AE_MODE, CONTROL_AE_MODE_ON);
-
- List<String> supportedFlashModes = p.getSupportedFlashModes();
-
- String flashModeSetting = null;
-
- // Flash is OFF by default, on cameras that support flash
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_OFF)) {
- flashModeSetting = Parameters.FLASH_MODE_OFF;
- }
-
- /*
- * Map all of the control.aeMode* enums, but ignore AE_MODE_OFF since we never support it
- */
-
- // Ignore flash.mode controls unless aeMode == ON
- if (aeMode == CONTROL_AE_MODE_ON) {
- if (flashMode == FLASH_MODE_TORCH) {
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_TORCH)) {
- flashModeSetting = Parameters.FLASH_MODE_TORCH;
- } else {
- Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == TORCH;" +
- "camera does not support it");
- }
- } else if (flashMode == FLASH_MODE_SINGLE) {
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
- flashModeSetting = Parameters.FLASH_MODE_ON;
- } else {
- Log.w(TAG, "mapAeAndFlashMode - Ignore flash.mode == SINGLE;" +
- "camera does not support it");
- }
- } else {
- // Use the default FLASH_MODE_OFF
- }
- } else if (aeMode == CONTROL_AE_MODE_ON_ALWAYS_FLASH) {
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_ON)) {
- flashModeSetting = Parameters.FLASH_MODE_ON;
- } else {
- Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_ALWAYS_FLASH;" +
- "camera does not support it");
- }
- } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_AUTO)) {
- flashModeSetting = Parameters.FLASH_MODE_AUTO;
- } else {
- Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH;" +
- "camera does not support it");
- }
- } else if (aeMode == CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE) {
- if (ListUtils.listContains(supportedFlashModes, Parameters.FLASH_MODE_RED_EYE)) {
- flashModeSetting = Parameters.FLASH_MODE_RED_EYE;
- } else {
- Log.w(TAG, "mapAeAndFlashMode - Ignore control.aeMode == ON_AUTO_FLASH_REDEYE;"
- + "camera does not support it");
- }
- } else {
- // Default to aeMode == ON, flash = OFF
- }
-
- if (flashModeSetting != null) {
- p.setFlashMode(flashModeSetting);
- }
-
- if (DEBUG) {
- Log.v(TAG,
- "mapAeAndFlashMode - set flash.mode (api1) to " + flashModeSetting
- + ", requested (api2) " + flashMode
- + ", supported (api1) " + ListUtils.listToString(supportedFlashModes));
- }
- }
-
- /**
- * Returns null if the anti-banding mode enum is not supported.
- */
- private static String convertAeAntiBandingModeToLegacy(int mode) {
- switch (mode) {
- case CONTROL_AE_ANTIBANDING_MODE_OFF: {
- return Parameters.ANTIBANDING_OFF;
- }
- case CONTROL_AE_ANTIBANDING_MODE_50HZ: {
- return Parameters.ANTIBANDING_50HZ;
- }
- case CONTROL_AE_ANTIBANDING_MODE_60HZ: {
- return Parameters.ANTIBANDING_60HZ;
- }
- case CONTROL_AE_ANTIBANDING_MODE_AUTO: {
- return Parameters.ANTIBANDING_AUTO;
- }
- default: {
- return null;
- }
- }
- }
-
- private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
- int[] legacyFps = new int[2];
- legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000;
- legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000;
- return legacyFps;
- }
-
- private static String convertAwbModeToLegacy(int mode) {
- switch (mode) {
- case CONTROL_AWB_MODE_AUTO:
- return Camera.Parameters.WHITE_BALANCE_AUTO;
- case CONTROL_AWB_MODE_INCANDESCENT:
- return Camera.Parameters.WHITE_BALANCE_INCANDESCENT;
- case CONTROL_AWB_MODE_FLUORESCENT:
- return Camera.Parameters.WHITE_BALANCE_FLUORESCENT;
- case CONTROL_AWB_MODE_WARM_FLUORESCENT:
- return Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT;
- case CONTROL_AWB_MODE_DAYLIGHT:
- return Camera.Parameters.WHITE_BALANCE_DAYLIGHT;
- case CONTROL_AWB_MODE_CLOUDY_DAYLIGHT:
- return Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT;
- case CONTROL_AWB_MODE_TWILIGHT:
- return Camera.Parameters.WHITE_BALANCE_TWILIGHT;
- case CONTROL_AWB_MODE_SHADE:
- return Parameters.WHITE_BALANCE_SHADE;
- default:
- Log.w(TAG, "convertAwbModeToLegacy - unrecognized control.awbMode" + mode);
- return Camera.Parameters.WHITE_BALANCE_AUTO;
- }
- }
-
-
- /**
- * Return {@code null} if the value is not supported, otherwise return the retrieved key's
- * value from the request (or the default value if it wasn't set).
- *
- * <p>If the fetched value in the request is equivalent to {@code allowedValue},
- * then omit the warning (e.g. turning off AF lock on a camera
- * that always has the AF lock turned off is a silent no-op), but still return {@code null}.</p>
- *
- * <p>Logs a warning to logcat if the key is not supported by api1 camera device.</p.
- */
- private static <T> T getIfSupported(
- CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue, boolean isSupported,
- T allowedValue) {
- T val = ParamsUtils.getOrDefault(r, key, defaultValue);
-
- if (!isSupported) {
- if (!Objects.equals(val, allowedValue)) {
- Log.w(TAG, key.getName() + " is not supported; ignoring requested value " + val);
- }
- return null;
- }
-
- return val;
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
deleted file mode 100644
index 09edf74f0d4c..000000000000
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.legacy.ParameterUtils.WeightedRectangle;
-import android.hardware.camera2.legacy.ParameterUtils.ZoomData;
-import android.hardware.camera2.params.MeteringRectangle;
-import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.util.Log;
-import android.util.Size;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static android.hardware.camera2.CaptureResult.*;
-
-/**
- * Provide legacy-specific implementations of camera2 CaptureResult for legacy devices.
- */
-@SuppressWarnings("deprecation")
-public class LegacyResultMapper {
- private static final String TAG = "LegacyResultMapper";
- private static final boolean DEBUG = false;
-
- private LegacyRequest mCachedRequest = null;
- private CameraMetadataNative mCachedResult = null;
-
- /**
- * Generate capture result metadata from the legacy camera request.
- *
- * <p>This method caches and reuses the result from the previous call to this method if
- * the {@code parameters} of the subsequent {@link LegacyRequest} passed to this method
- * have not changed.</p>
- *
- * @param legacyRequest a non-{@code null} legacy request containing the latest parameters
- * @param timestamp the timestamp to use for this result in nanoseconds.
- *
- * @return {@link CameraMetadataNative} object containing result metadata.
- */
- public CameraMetadataNative cachedConvertResultMetadata(
- LegacyRequest legacyRequest, long timestamp) {
- CameraMetadataNative result;
- boolean cached;
-
- /*
- * Attempt to look up the result from the cache if the parameters haven't changed
- */
- if (mCachedRequest != null &&
- legacyRequest.parameters.same(mCachedRequest.parameters) &&
- legacyRequest.captureRequest.equals(mCachedRequest.captureRequest)) {
- result = new CameraMetadataNative(mCachedResult);
- cached = true;
- } else {
- result = convertResultMetadata(legacyRequest);
- cached = false;
-
- // Always cache a *copy* of the metadata result,
- // since api2's client side takes ownership of it after it receives a result
- mCachedRequest = legacyRequest;
- mCachedResult = new CameraMetadataNative(result);
- }
-
- /*
- * Unconditionally set fields that change in every single frame
- */
- {
- // sensor.timestamp
- result.set(SENSOR_TIMESTAMP, timestamp);
- }
-
- if (DEBUG) {
- Log.v(TAG, "cachedConvertResultMetadata - cached? " + cached +
- " timestamp = " + timestamp);
-
- Log.v(TAG, "----- beginning of result dump ------");
- result.dumpToLog();
- Log.v(TAG, "----- end of result dump ------");
- }
-
- return result;
- }
-
- /**
- * Generate capture result metadata from the legacy camera request.
- *
- * @param legacyRequest a non-{@code null} legacy request containing the latest parameters
- * @return a {@link CameraMetadataNative} object containing result metadata.
- */
- private static CameraMetadataNative convertResultMetadata(LegacyRequest legacyRequest) {
- CameraCharacteristics characteristics = legacyRequest.characteristics;
- CaptureRequest request = legacyRequest.captureRequest;
- Size previewSize = legacyRequest.previewSize;
- Camera.Parameters params = legacyRequest.parameters;
-
- CameraMetadataNative result = new CameraMetadataNative();
-
- Rect activeArraySize = characteristics.get(
- CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- ZoomData zoomData = ParameterUtils.convertToLegacyZoom(activeArraySize,
- request.get(CaptureRequest.SCALER_CROP_REGION),
- request.get(CaptureRequest.CONTROL_ZOOM_RATIO),
- previewSize, params);
-
- /*
- * colorCorrection
- */
- // colorCorrection.aberrationMode
- {
- result.set(COLOR_CORRECTION_ABERRATION_MODE,
- request.get(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE));
- }
-
- /*
- * control
- */
-
- /*
- * control.ae*
- */
- mapAe(result, characteristics, request, activeArraySize, zoomData, /*out*/params);
-
- /*
- * control.af*
- */
- mapAf(result, activeArraySize, zoomData, /*out*/params);
-
- /*
- * control.awb*
- */
- mapAwb(result, /*out*/params);
-
- /*
- * control.captureIntent
- */
- {
- int captureIntent = ParamsUtils.getOrDefault(request,
- CaptureRequest.CONTROL_CAPTURE_INTENT,
- /*defaultValue*/CaptureRequest.CONTROL_CAPTURE_INTENT_PREVIEW);
-
- captureIntent = LegacyRequestMapper.filterSupportedCaptureIntent(captureIntent);
-
- result.set(CONTROL_CAPTURE_INTENT, captureIntent);
- }
-
- /*
- * control.mode
- */
- {
- int controlMode = ParamsUtils.getOrDefault(request, CaptureRequest.CONTROL_MODE,
- CONTROL_MODE_AUTO);
- if (controlMode == CaptureResult.CONTROL_MODE_USE_SCENE_MODE) {
- result.set(CONTROL_MODE, CONTROL_MODE_USE_SCENE_MODE);
- } else {
- result.set(CONTROL_MODE, CONTROL_MODE_AUTO);
- }
- }
-
- /*
- * control.sceneMode
- */
- {
- String legacySceneMode = params.getSceneMode();
- int mode = LegacyMetadataMapper.convertSceneModeFromLegacy(legacySceneMode);
- if (mode != LegacyMetadataMapper.UNKNOWN_MODE) {
- result.set(CaptureResult.CONTROL_SCENE_MODE, mode);
- // In case of SCENE_MODE == FACE_PRIORITY, LegacyFaceDetectMapper will override
- // the result to say SCENE_MODE == FACE_PRIORITY.
- } else {
- Log.w(TAG, "Unknown scene mode " + legacySceneMode +
- " returned by camera HAL, setting to disabled.");
- result.set(CaptureResult.CONTROL_SCENE_MODE, CONTROL_SCENE_MODE_DISABLED);
- }
- }
-
- /*
- * control.effectMode
- */
- {
- String legacyEffectMode = params.getColorEffect();
- int mode = LegacyMetadataMapper.convertEffectModeFromLegacy(legacyEffectMode);
- if (mode != LegacyMetadataMapper.UNKNOWN_MODE) {
- result.set(CaptureResult.CONTROL_EFFECT_MODE, mode);
- } else {
- Log.w(TAG, "Unknown effect mode " + legacyEffectMode +
- " returned by camera HAL, setting to off.");
- result.set(CaptureResult.CONTROL_EFFECT_MODE, CONTROL_EFFECT_MODE_OFF);
- }
- }
-
- // control.videoStabilizationMode
- {
- int stabMode =
- (params.isVideoStabilizationSupported() && params.getVideoStabilization()) ?
- CONTROL_VIDEO_STABILIZATION_MODE_ON :
- CONTROL_VIDEO_STABILIZATION_MODE_OFF;
- result.set(CONTROL_VIDEO_STABILIZATION_MODE, stabMode);
- }
-
- /*
- * flash
- */
- {
- // flash.mode, flash.state mapped in mapAeAndFlashMode
- }
-
- /*
- * lens
- */
- // lens.focusDistance
- {
- if (Parameters.FOCUS_MODE_INFINITY.equals(params.getFocusMode())) {
- result.set(CaptureResult.LENS_FOCUS_DISTANCE, 0.0f);
- }
- }
-
- // lens.focalLength
- result.set(CaptureResult.LENS_FOCAL_LENGTH, params.getFocalLength());
-
- /*
- * request
- */
- // request.pipelineDepth
- result.set(REQUEST_PIPELINE_DEPTH,
- characteristics.get(CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH));
-
- /*
- * scaler
- */
- mapScaler(result, zoomData, /*out*/params);
-
- /*
- * sensor
- */
- // sensor.timestamp varies every frame; mapping is done in #cachedConvertResultMetadata
- {
- // Unconditionally no test patterns
- result.set(SENSOR_TEST_PATTERN_MODE, SENSOR_TEST_PATTERN_MODE_OFF);
- }
-
- /*
- * jpeg
- */
- // jpeg.gpsLocation
- result.set(JPEG_GPS_LOCATION, request.get(CaptureRequest.JPEG_GPS_LOCATION));
-
- // jpeg.orientation
- result.set(JPEG_ORIENTATION, request.get(CaptureRequest.JPEG_ORIENTATION));
-
- // jpeg.quality
- result.set(JPEG_QUALITY, (byte) params.getJpegQuality());
-
- // jpeg.thumbnailQuality
- result.set(JPEG_THUMBNAIL_QUALITY, (byte) params.getJpegThumbnailQuality());
-
- // jpeg.thumbnailSize
- Camera.Size s = params.getJpegThumbnailSize();
- if (s != null) {
- result.set(JPEG_THUMBNAIL_SIZE, ParameterUtils.convertSize(s));
- } else {
- Log.w(TAG, "Null thumbnail size received from parameters.");
- }
-
- /*
- * noiseReduction.*
- */
- // noiseReduction.mode
- result.set(NOISE_REDUCTION_MODE, request.get(CaptureRequest.NOISE_REDUCTION_MODE));
-
- return result;
- }
-
- private static void mapAe(CameraMetadataNative m,
- CameraCharacteristics characteristics,
- CaptureRequest request, Rect activeArray, ZoomData zoomData, /*out*/Parameters p) {
- // control.aeAntiBandingMode
- {
- int antiBandingMode = LegacyMetadataMapper.convertAntiBandingModeOrDefault(
- p.getAntibanding());
- m.set(CONTROL_AE_ANTIBANDING_MODE, antiBandingMode);
- }
-
- // control.aeExposureCompensation
- {
- m.set(CONTROL_AE_EXPOSURE_COMPENSATION, p.getExposureCompensation());
- }
-
- // control.aeLock
- {
- boolean lock = p.isAutoExposureLockSupported() ? p.getAutoExposureLock() : false;
- m.set(CONTROL_AE_LOCK, lock);
- if (DEBUG) {
- Log.v(TAG,
- "mapAe - android.control.aeLock = " + lock +
- ", supported = " + p.isAutoExposureLockSupported());
- }
-
- Boolean requestLock = request.get(CaptureRequest.CONTROL_AE_LOCK);
- if (requestLock != null && requestLock != lock) {
- Log.w(TAG,
- "mapAe - android.control.aeLock was requested to " + requestLock +
- " but resulted in " + lock);
- }
- }
-
- // control.aeMode, flash.mode, flash.state
- mapAeAndFlashMode(m, characteristics, p);
-
- // control.aeState
- if (LegacyMetadataMapper.LIE_ABOUT_AE_STATE) {
- // Lie to pass CTS temporarily.
- // TODO: Implement precapture trigger, after which we can report CONVERGED ourselves
- m.set(CONTROL_AE_STATE, CONTROL_AE_STATE_CONVERGED);
- }
-
- // control.aeRegions
- if (p.getMaxNumMeteringAreas() > 0) {
- if (DEBUG) {
- String meteringAreas = p.get("metering-areas");
- Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas);
- }
-
- MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
- zoomData, p.getMeteringAreas(), "AE");
-
- m.set(CONTROL_AE_REGIONS, meteringRectArray);
- }
-
- }
-
- private static void mapAf(CameraMetadataNative m,
- Rect activeArray, ZoomData zoomData, Camera.Parameters p) {
- // control.afMode
- m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode()));
-
- // control.afRegions
- if (p.getMaxNumFocusAreas() > 0) {
- if (DEBUG) {
- String focusAreas = p.get("focus-areas");
- Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas);
- }
-
- MeteringRectangle[] meteringRectArray = getMeteringRectangles(activeArray,
- zoomData, p.getFocusAreas(), "AF");
-
- m.set(CONTROL_AF_REGIONS, meteringRectArray);
- }
- }
-
- private static void mapAwb(CameraMetadataNative m, Camera.Parameters p) {
- // control.awbLock
- {
- boolean lock = p.isAutoWhiteBalanceLockSupported() ?
- p.getAutoWhiteBalanceLock() : false;
- m.set(CONTROL_AWB_LOCK, lock);
- }
-
- // control.awbMode
- {
- int awbMode = convertLegacyAwbMode(p.getWhiteBalance());
- m.set(CONTROL_AWB_MODE, awbMode);
- }
- }
-
- private static MeteringRectangle[] getMeteringRectangles(Rect activeArray, ZoomData zoomData,
- List<Camera.Area> meteringAreaList, String regionName) {
- List<MeteringRectangle> meteringRectList = new ArrayList<>();
- if (meteringAreaList != null) {
- for (Camera.Area area : meteringAreaList) {
- WeightedRectangle rect =
- ParameterUtils.convertCameraAreaToActiveArrayRectangle(
- activeArray, zoomData, area);
-
- meteringRectList.add(rect.toMetering());
- }
- }
-
- if (DEBUG) {
- Log.v(TAG,
- "Metering rectangles for " + regionName + ": "
- + ListUtils.listToString(meteringRectList));
- }
-
- return meteringRectList.toArray(new MeteringRectangle[0]);
- }
-
- /** Map results for control.aeMode, flash.mode, flash.state */
- private static void mapAeAndFlashMode(CameraMetadataNative m,
- CameraCharacteristics characteristics, Parameters p) {
- // Default: AE mode on but flash never fires
- int flashMode = FLASH_MODE_OFF;
- // If there is no flash on this camera, the state is always unavailable
- // , otherwise it's only known for TORCH/SINGLE modes
- Integer flashState = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
- ? null : FLASH_STATE_UNAVAILABLE;
- int aeMode = CONTROL_AE_MODE_ON;
-
- String flashModeSetting = p.getFlashMode();
-
- if (flashModeSetting != null) {
- switch (flashModeSetting) {
- case Parameters.FLASH_MODE_OFF:
- break; // ok, using default
- case Parameters.FLASH_MODE_AUTO:
- aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH;
- break;
- case Parameters.FLASH_MODE_ON:
- // flashMode = SINGLE + aeMode = ON is indistinguishable from ON_ALWAYS_FLASH
- flashMode = FLASH_MODE_SINGLE;
- aeMode = CONTROL_AE_MODE_ON_ALWAYS_FLASH;
- flashState = FLASH_STATE_FIRED;
- break;
- case Parameters.FLASH_MODE_RED_EYE:
- aeMode = CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE;
- break;
- case Parameters.FLASH_MODE_TORCH:
- flashMode = FLASH_MODE_TORCH;
- flashState = FLASH_STATE_FIRED;
- break;
- default:
- Log.w(TAG,
- "mapAeAndFlashMode - Ignoring unknown flash mode " + p.getFlashMode());
- }
- }
-
- // flash.state
- m.set(FLASH_STATE, flashState);
- // flash.mode
- m.set(FLASH_MODE, flashMode);
- // control.aeMode
- m.set(CONTROL_AE_MODE, aeMode);
- }
-
- private static int convertLegacyAfMode(String mode) {
- if (mode == null) {
- Log.w(TAG, "convertLegacyAfMode - no AF mode, default to OFF");
- return CONTROL_AF_MODE_OFF;
- }
-
- switch (mode) {
- case Parameters.FOCUS_MODE_AUTO:
- return CONTROL_AF_MODE_AUTO;
- case Parameters.FOCUS_MODE_CONTINUOUS_PICTURE:
- return CONTROL_AF_MODE_CONTINUOUS_PICTURE;
- case Parameters.FOCUS_MODE_CONTINUOUS_VIDEO:
- return CONTROL_AF_MODE_CONTINUOUS_VIDEO;
- case Parameters.FOCUS_MODE_EDOF:
- return CONTROL_AF_MODE_EDOF;
- case Parameters.FOCUS_MODE_MACRO:
- return CONTROL_AF_MODE_MACRO;
- case Parameters.FOCUS_MODE_FIXED:
- return CONTROL_AF_MODE_OFF;
- case Parameters.FOCUS_MODE_INFINITY:
- return CONTROL_AF_MODE_OFF;
- default:
- Log.w(TAG, "convertLegacyAfMode - unknown mode " + mode + " , ignoring");
- return CONTROL_AF_MODE_OFF;
- }
- }
-
- private static int convertLegacyAwbMode(String mode) {
- if (mode == null) {
- // OK: camera1 api may not support changing WB modes; assume AUTO
- return CONTROL_AWB_MODE_AUTO;
- }
-
- switch (mode) {
- case Camera.Parameters.WHITE_BALANCE_AUTO:
- return CONTROL_AWB_MODE_AUTO;
- case Camera.Parameters.WHITE_BALANCE_INCANDESCENT:
- return CONTROL_AWB_MODE_INCANDESCENT;
- case Camera.Parameters.WHITE_BALANCE_FLUORESCENT:
- return CONTROL_AWB_MODE_FLUORESCENT;
- case Camera.Parameters.WHITE_BALANCE_WARM_FLUORESCENT:
- return CONTROL_AWB_MODE_WARM_FLUORESCENT;
- case Camera.Parameters.WHITE_BALANCE_DAYLIGHT:
- return CONTROL_AWB_MODE_DAYLIGHT;
- case Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT:
- return CONTROL_AWB_MODE_CLOUDY_DAYLIGHT;
- case Camera.Parameters.WHITE_BALANCE_TWILIGHT:
- return CONTROL_AWB_MODE_TWILIGHT;
- case Camera.Parameters.WHITE_BALANCE_SHADE:
- return CONTROL_AWB_MODE_SHADE;
- default:
- Log.w(TAG, "convertAwbMode - unrecognized WB mode " + mode);
- return CONTROL_AWB_MODE_AUTO;
- }
- }
-
- /** Map results for scaler.* */
- private static void mapScaler(CameraMetadataNative m,
- ZoomData zoomData,
- /*out*/Parameters p) {
- /*
- * scaler.cropRegion
- */
- {
- m.set(SCALER_CROP_REGION, zoomData.reportedCrop);
- }
-
- /*
- * control.zoomRatio
- */
- {
- m.set(CONTROL_ZOOM_RATIO, zoomData.reportedZoomRatio);
- }
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/ParameterUtils.java b/core/java/android/hardware/camera2/legacy/ParameterUtils.java
deleted file mode 100644
index eb435989e9a0..000000000000
--- a/core/java/android/hardware/camera2/legacy/ParameterUtils.java
+++ /dev/null
@@ -1,1099 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.Matrix;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.hardware.Camera;
-import android.hardware.Camera.Area;
-import android.hardware.camera2.params.Face;
-import android.hardware.camera2.params.MeteringRectangle;
-import android.hardware.camera2.utils.ListUtils;
-import android.hardware.camera2.utils.ParamsUtils;
-import android.hardware.camera2.utils.SizeAreaComparator;
-import android.util.Size;
-import android.util.SizeF;
-
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Various utilities for dealing with camera API1 parameters.
- */
-@SuppressWarnings("deprecation")
-public class ParameterUtils {
- /** Upper/left minimal point of a normalized rectangle */
- public static final int NORMALIZED_RECTANGLE_MIN = -1000;
- /** Lower/right maximal point of a normalized rectangle */
- public static final int NORMALIZED_RECTANGLE_MAX = 1000;
- /** The default normalized rectangle spans the entire size of the preview viewport */
- public static final Rect NORMALIZED_RECTANGLE_DEFAULT = new Rect(
- NORMALIZED_RECTANGLE_MIN,
- NORMALIZED_RECTANGLE_MIN,
- NORMALIZED_RECTANGLE_MAX,
- NORMALIZED_RECTANGLE_MAX);
- /** The default normalized area uses the default normalized rectangle with a weight=1 */
- public static final Camera.Area CAMERA_AREA_DEFAULT =
- new Camera.Area(new Rect(NORMALIZED_RECTANGLE_DEFAULT),
- /*weight*/1);
- /** Empty rectangle {@code 0x0+0,0} */
- public static final Rect RECTANGLE_EMPTY =
- new Rect(/*left*/0, /*top*/0, /*right*/0, /*bottom*/0);
-
- private static final double ASPECT_RATIO_TOLERANCE = 0.05f;
-
- /**
- * Calculate effective/reported zoom data from a user-specified crop region.
- */
- public static class ZoomData {
- /** Zoom index used by {@link Camera.Parameters#setZoom} */
- public final int zoomIndex;
- /** Effective crop-region given the zoom index, coordinates relative to active-array */
- public final Rect previewCrop;
- /** Reported crop-region given the zoom index, coordinates relative to active-array */
- public final Rect reportedCrop;
- /** Reported zoom ratio given the zoom index */
- public final float reportedZoomRatio;
-
- public ZoomData(int zoomIndex, Rect previewCrop, Rect reportedCrop,
- float reportedZoomRatio) {
- this.zoomIndex = zoomIndex;
- this.previewCrop = previewCrop;
- this.reportedCrop = reportedCrop;
- this.reportedZoomRatio = reportedZoomRatio;
- }
- }
-
- /**
- * Calculate effective/reported metering data from a user-specified metering region.
- */
- public static class MeteringData {
- /**
- * The metering area scaled to the range of [-1000, 1000].
- * <p>Values outside of this range are clipped to be within the range.</p>
- */
- public final Camera.Area meteringArea;
- /**
- * Effective preview metering region, coordinates relative to active-array.
- *
- * <p>Clipped to fit inside of the (effective) preview crop region.</p>
- */
- public final Rect previewMetering;
- /**
- * Reported metering region, coordinates relative to active-array.
- *
- * <p>Clipped to fit inside of the (reported) resulting crop region.</p>
- */
- public final Rect reportedMetering;
-
- public MeteringData(Area meteringArea, Rect previewMetering, Rect reportedMetering) {
- this.meteringArea = meteringArea;
- this.previewMetering = previewMetering;
- this.reportedMetering = reportedMetering;
- }
- }
-
- /**
- * A weighted rectangle is an arbitrary rectangle (the coordinate system is unknown) with an
- * arbitrary weight.
- *
- * <p>The user of this class must know what the coordinate system ahead of time; it's
- * then possible to convert to a more concrete type such as a metering rectangle or a face.
- * </p>
- *
- * <p>When converting to a more concrete type, out-of-range values are clipped; this prevents
- * possible illegal argument exceptions being thrown at runtime.</p>
- */
- public static class WeightedRectangle {
- /** Arbitrary rectangle (the range is user-defined); never {@code null}. */
- public final Rect rect;
- /** Arbitrary weight (the range is user-defined). */
- public final int weight;
-
- /**
- * Create a new weighted-rectangle from a non-{@code null} rectangle; the {@code weight}
- * can be unbounded.
- */
- public WeightedRectangle(Rect rect, int weight) {
- this.rect = checkNotNull(rect, "rect must not be null");
- this.weight = weight;
- }
-
- /**
- * Convert to a metering rectangle, clipping any of the values to stay within range.
- *
- * <p>If values are clipped, a warning is printed to logcat.</p>
- *
- * @return a new metering rectangle
- */
- public MeteringRectangle toMetering() {
- int weight = clip(this.weight,
- MeteringRectangle.METERING_WEIGHT_MIN,
- MeteringRectangle.METERING_WEIGHT_MAX,
- rect,
- "weight");
-
- int x = clipLower(rect.left, /*lo*/0, rect, "left");
- int y = clipLower(rect.top, /*lo*/0, rect, "top");
- int w = clipLower(rect.width(), /*lo*/0, rect, "width");
- int h = clipLower(rect.height(), /*lo*/0, rect, "height");
-
- return new MeteringRectangle(x, y, w, h, weight);
- }
-
- /**
- * Convert to a face; the rect is considered to be the bounds, and the weight
- * is considered to be the score.
- *
- * <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX},
- * the score is clipped first and a warning is printed to logcat.</p>
- *
- * <p>If the id is negative, the id is changed to 0 and a warning is printed to
- * logcat.</p>
- *
- * <p>All other parameters are passed-through as-is.</p>
- *
- * @return a new face with the optional features set
- */
- public Face toFace(
- int id, Point leftEyePosition, Point rightEyePosition, Point mouthPosition) {
- int idSafe = clipLower(id, /*lo*/0, rect, "id");
- int score = clip(weight,
- Face.SCORE_MIN,
- Face.SCORE_MAX,
- rect,
- "score");
-
- return new Face(rect, score, idSafe, leftEyePosition, rightEyePosition, mouthPosition);
- }
-
- /**
- * Convert to a face; the rect is considered to be the bounds, and the weight
- * is considered to be the score.
- *
- * <p>If the score is out of range of {@value Face#SCORE_MIN}, {@value Face#SCORE_MAX},
- * the score is clipped first and a warning is printed to logcat.</p>
- *
- * <p>All other parameters are passed-through as-is.</p>
- *
- * @return a new face without the optional features
- */
- public Face toFace() {
- int score = clip(weight,
- Face.SCORE_MIN,
- Face.SCORE_MAX,
- rect,
- "score");
-
- return new Face(rect, score);
- }
-
- private static int clipLower(int value, int lo, Rect rect, String name) {
- return clip(value, lo, /*hi*/Integer.MAX_VALUE, rect, name);
- }
-
- private static int clip(int value, int lo, int hi, Rect rect, String name) {
- if (value < lo) {
- Log.w(TAG, "toMetering - Rectangle " + rect + " "
- + name + " too small, clip to " + lo);
- value = lo;
- } else if (value > hi) {
- Log.w(TAG, "toMetering - Rectangle " + rect + " "
- + name + " too small, clip to " + hi);
- value = hi;
- }
-
- return value;
- }
- }
-
- private static final String TAG = "ParameterUtils";
- private static final boolean DEBUG = false;
-
- /** getZoomRatios stores zoom ratios in 1/100 increments, e.x. a zoom of 3.2 is 320 */
- private static final int ZOOM_RATIO_MULTIPLIER = 100;
-
- /**
- * Convert a camera API1 size into a util size
- */
- public static Size convertSize(Camera.Size size) {
- checkNotNull(size, "size must not be null");
-
- return new Size(size.width, size.height);
- }
-
- /**
- * Convert a camera API1 list of sizes into a util list of sizes
- */
- public static List<Size> convertSizeList(List<Camera.Size> sizeList) {
- checkNotNull(sizeList, "sizeList must not be null");
-
- List<Size> sizes = new ArrayList<>(sizeList.size());
- for (Camera.Size s : sizeList) {
- sizes.add(new Size(s.width, s.height));
- }
- return sizes;
- }
-
- /**
- * Convert a camera API1 list of sizes into an array of sizes
- */
- public static Size[] convertSizeListToArray(List<Camera.Size> sizeList) {
- checkNotNull(sizeList, "sizeList must not be null");
-
- Size[] array = new Size[sizeList.size()];
- int ctr = 0;
- for (Camera.Size s : sizeList) {
- array[ctr++] = new Size(s.width, s.height);
- }
- return array;
- }
-
- /**
- * Check if the camera API1 list of sizes contains a size with the given dimens.
- */
- public static boolean containsSize(List<Camera.Size> sizeList, int width, int height) {
- checkNotNull(sizeList, "sizeList must not be null");
- for (Camera.Size s : sizeList) {
- if (s.height == height && s.width == width) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns the largest supported picture size, as compared by its area.
- */
- public static Size getLargestSupportedJpegSizeByArea(Camera.Parameters params) {
- checkNotNull(params, "params must not be null");
-
- List<Size> supportedJpegSizes = convertSizeList(params.getSupportedPictureSizes());
- return SizeAreaComparator.findLargestByArea(supportedJpegSizes);
- }
-
- /**
- * Convert a camera area into a human-readable string.
- */
- public static String stringFromArea(Camera.Area area) {
- if (area == null) {
- return null;
- } else {
- StringBuilder sb = new StringBuilder();
- Rect r = area.rect;
-
- sb.setLength(0);
- sb.append("(["); sb.append(r.left); sb.append(',');
- sb.append(r.top); sb.append("]["); sb.append(r.right);
- sb.append(','); sb.append(r.bottom); sb.append(']');
-
- sb.append(',');
- sb.append(area.weight);
- sb.append(')');
-
- return sb.toString();
- }
- }
-
- /**
- * Convert a camera area list into a human-readable string
- * @param areaList a list of areas (null is ok)
- */
- public static String stringFromAreaList(List<Camera.Area> areaList) {
- StringBuilder sb = new StringBuilder();
-
- if (areaList == null) {
- return null;
- }
-
- int i = 0;
- for (Camera.Area area : areaList) {
- if (area == null) {
- sb.append("null");
- } else {
- sb.append(stringFromArea(area));
- }
-
- if (i != areaList.size() - 1) {
- sb.append(", ");
- }
-
- i++;
- }
-
- return sb.toString();
- }
-
- /**
- * Calculate the closest zoom index for the user-requested crop region by rounding
- * up to the closest (largest or equal) possible zoom crop.
- *
- * <p>If the requested crop region exceeds the size of the active array, it is
- * shrunk to fit inside of the active array first.</p>
- *
- * <p>Since all api1 camera devices only support a discrete set of zooms, we have
- * to translate the per-pixel-granularity requested crop region into a per-zoom-index
- * granularity.</p>
- *
- * <p>Furthermore, since the zoom index and zoom levels also depends on the field-of-view
- * of the preview, the current preview {@code streamSize} is also used.</p>
- *
- * <p>The calculated crop regions are then written to in-place to {@code reportedCropRegion}
- * and {@code previewCropRegion}, in coordinates relative to the active array.</p>
- *
- * @param params non-{@code null} camera api1 parameters
- * @param activeArray active array dimensions, in sensor space
- * @param streamSize stream size dimensions, in pixels
- * @param cropRegion user-specified crop region, in active array coordinates
- * @param reportedCropRegion (out parameter) what the result for {@code cropRegion} looks like
- * @param previewCropRegion (out parameter) what the visual preview crop is
- * @return
- * the zoom index inclusively between 0 and {@code Parameters#getMaxZoom},
- * where 0 means the camera is not zoomed
- *
- * @throws NullPointerException if any of the args were {@code null}
- */
- public static int getClosestAvailableZoomCrop(
- Camera.Parameters params, Rect activeArray,
- Size streamSize, Rect cropRegion,
- /*out*/
- Rect reportedCropRegion,
- Rect previewCropRegion) {
- checkNotNull(params, "params must not be null");
- checkNotNull(activeArray, "activeArray must not be null");
- checkNotNull(streamSize, "streamSize must not be null");
- checkNotNull(reportedCropRegion, "reportedCropRegion must not be null");
- checkNotNull(previewCropRegion, "previewCropRegion must not be null");
-
- Rect actualCrop = new Rect(cropRegion);
-
- /*
- * Shrink requested crop region to fit inside of the active array size
- */
- if (!actualCrop.intersect(activeArray)) {
- Log.w(TAG, "getClosestAvailableZoomCrop - Crop region out of range; " +
- "setting to active array size");
- actualCrop.set(activeArray);
- }
-
- Rect previewCrop = getPreviewCropRectangleUnzoomed(activeArray, streamSize);
-
- // Make the user-requested crop region the same aspect ratio as the preview stream size
- Rect cropRegionAsPreview =
- shrinkToSameAspectRatioCentered(previewCrop, actualCrop);
-
- if (DEBUG) {
- Log.v(TAG, "getClosestAvailableZoomCrop - actualCrop = " + actualCrop);
- Log.v(TAG,
- "getClosestAvailableZoomCrop - previewCrop = " + previewCrop);
- Log.v(TAG,
- "getClosestAvailableZoomCrop - cropRegionAsPreview = " + cropRegionAsPreview);
- }
-
- /*
- * Iterate all available zoom rectangles and find the closest zoom index
- */
- Rect bestReportedCropRegion = null;
- Rect bestPreviewCropRegion = null;
- int bestZoomIndex = -1;
-
- List<Rect> availableReportedCropRegions =
- getAvailableZoomCropRectangles(params, activeArray);
- List<Rect> availablePreviewCropRegions =
- getAvailablePreviewZoomCropRectangles(params, activeArray, streamSize);
-
- if (DEBUG) {
- Log.v(TAG,
- "getClosestAvailableZoomCrop - availableReportedCropRegions = " +
- ListUtils.listToString(availableReportedCropRegions));
- Log.v(TAG,
- "getClosestAvailableZoomCrop - availablePreviewCropRegions = " +
- ListUtils.listToString(availablePreviewCropRegions));
- }
-
- if (availableReportedCropRegions.size() != availablePreviewCropRegions.size()) {
- throw new AssertionError("available reported/preview crop region size mismatch");
- }
-
- for (int i = 0; i < availableReportedCropRegions.size(); ++i) {
- Rect currentPreviewCropRegion = availablePreviewCropRegions.get(i);
- Rect currentReportedCropRegion = availableReportedCropRegions.get(i);
-
- boolean isBest;
- if (bestZoomIndex == -1) {
- isBest = true;
- } else if (currentPreviewCropRegion.width() >= cropRegionAsPreview.width() &&
- currentPreviewCropRegion.height() >= cropRegionAsPreview.height()) {
- isBest = true;
- } else {
- isBest = false;
- }
-
- // Sizes are sorted largest-to-smallest, so once the available crop is too small,
- // we the rest are too small. Furthermore, this is the final best crop,
- // since its the largest crop that still fits the requested crop
- if (isBest) {
- bestPreviewCropRegion = currentPreviewCropRegion;
- bestReportedCropRegion = currentReportedCropRegion;
- bestZoomIndex = i;
- } else {
- break;
- }
- }
-
- if (bestZoomIndex == -1) {
- // Even in the worst case, we should always at least return 0 here
- throw new AssertionError("Should've found at least one valid zoom index");
- }
-
- // Write the rectangles in-place
- reportedCropRegion.set(bestReportedCropRegion);
- previewCropRegion.set(bestPreviewCropRegion);
-
- return bestZoomIndex;
- }
-
- /**
- * Calculate the effective crop rectangle for this preview viewport;
- * assumes the preview is centered to the sensor and scaled to fit across one of the dimensions
- * without skewing.
- *
- * <p>The preview size must be a subset of the active array size; the resulting
- * rectangle will also be a subset of the active array rectangle.</p>
- *
- * <p>The unzoomed crop rectangle is calculated only.</p>
- *
- * @param activeArray active array dimensions, in sensor space
- * @param previewSize size of the preview buffer render target, in pixels (not in sensor space)
- * @return a rectangle which serves as the preview stream's effective crop region (unzoomed),
- * in sensor space
- *
- * @throws NullPointerException
- * if any of the args were {@code null}
- * @throws IllegalArgumentException
- * if {@code previewSize} is wider or taller than {@code activeArray}
- */
- private static Rect getPreviewCropRectangleUnzoomed(Rect activeArray, Size previewSize) {
- if (previewSize.getWidth() > activeArray.width()) {
- throw new IllegalArgumentException("previewSize must not be wider than activeArray");
- } else if (previewSize.getHeight() > activeArray.height()) {
- throw new IllegalArgumentException("previewSize must not be taller than activeArray");
- }
-
- float aspectRatioArray = activeArray.width() * 1.0f / activeArray.height();
- float aspectRatioPreview = previewSize.getWidth() * 1.0f / previewSize.getHeight();
-
- float cropH, cropW;
- if (Math.abs(aspectRatioPreview - aspectRatioArray) < ASPECT_RATIO_TOLERANCE) {
- cropH = activeArray.height();
- cropW = activeArray.width();
- } else if (aspectRatioPreview < aspectRatioArray) {
- // The new width must be smaller than the height, so scale the width by AR
- cropH = activeArray.height();
- cropW = cropH * aspectRatioPreview;
- } else {
- // The new height must be smaller (or equal) than the width, so scale the height by AR
- cropW = activeArray.width();
- cropH = cropW / aspectRatioPreview;
- }
-
- Matrix translateMatrix = new Matrix();
- RectF cropRect = new RectF(/*left*/0, /*top*/0, cropW, cropH);
-
- // Now center the crop rectangle so its center is in the center of the active array
- translateMatrix.setTranslate(activeArray.exactCenterX(), activeArray.exactCenterY());
- translateMatrix.postTranslate(-cropRect.centerX(), -cropRect.centerY());
-
- translateMatrix.mapRect(/*inout*/cropRect);
-
- // Round the rect corners towards the nearest integer values
- return ParamsUtils.createRect(cropRect);
- }
-
- /**
- * Shrink the {@code shrinkTarget} rectangle to snugly fit inside of {@code reference};
- * the aspect ratio of {@code shrinkTarget} will change to be the same aspect ratio as
- * {@code reference}.
- *
- * <p>At most a single dimension will scale (down). Both dimensions will never be scaled.</p>
- *
- * @param reference the rectangle whose aspect ratio will be used as the new aspect ratio
- * @param shrinkTarget the rectangle which will be scaled down to have a new aspect ratio
- *
- * @return a new rectangle, a subset of {@code shrinkTarget},
- * whose aspect ratio will match that of {@code reference}
- */
- private static Rect shrinkToSameAspectRatioCentered(Rect reference, Rect shrinkTarget) {
- float aspectRatioReference = reference.width() * 1.0f / reference.height();
- float aspectRatioShrinkTarget = shrinkTarget.width() * 1.0f / shrinkTarget.height();
-
- float cropH, cropW;
- if (aspectRatioShrinkTarget < aspectRatioReference) {
- // The new width must be smaller than the height, so scale the width by AR
- cropH = reference.height();
- cropW = cropH * aspectRatioShrinkTarget;
- } else {
- // The new height must be smaller (or equal) than the width, so scale the height by AR
- cropW = reference.width();
- cropH = cropW / aspectRatioShrinkTarget;
- }
-
- Matrix translateMatrix = new Matrix();
- RectF shrunkRect = new RectF(shrinkTarget);
-
- // Scale the rectangle down, but keep its center in the same place as before
- translateMatrix.setScale(cropW / reference.width(), cropH / reference.height(),
- shrinkTarget.exactCenterX(), shrinkTarget.exactCenterY());
-
- translateMatrix.mapRect(/*inout*/shrunkRect);
-
- return ParamsUtils.createRect(shrunkRect);
- }
-
- /**
- * Get the available 'crop' (zoom) rectangles for this camera that will be reported
- * via a {@code CaptureResult} when a zoom is requested.
- *
- * <p>These crops ignores the underlying preview buffer size, and will always be reported
- * the same values regardless of what configuration of outputs is used.</p>
- *
- * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size,
- * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p>
- *
- * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize},
- * by shrinking the rectangle if necessary.</p>
- *
- * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize}
- * = {@code activeArray size}.</p>
- *
- * @param params non-{@code null} camera api1 parameters
- * @param activeArray active array dimensions, in sensor space
- * @param streamSize stream size dimensions, in pixels
- *
- * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
- */
- public static List<Rect> getAvailableZoomCropRectangles(
- Camera.Parameters params, Rect activeArray) {
- checkNotNull(params, "params must not be null");
- checkNotNull(activeArray, "activeArray must not be null");
-
- return getAvailableCropRectangles(params, activeArray, ParamsUtils.createSize(activeArray));
- }
-
- /**
- * Get the available 'crop' (zoom) rectangles for this camera.
- *
- * <p>This is the effective (real) crop that is applied by the camera api1 device
- * when projecting the zoom onto the intermediate preview buffer. Use this when
- * deciding which zoom ratio to apply.</p>
- *
- * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size,
- * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p>
- *
- * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize},
- * by shrinking the rectangle if necessary.</p>
- *
- * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize}
- * = {@code activeArray size}.</p>
- *
- * @param params non-{@code null} camera api1 parameters
- * @param activeArray active array dimensions, in sensor space
- * @param streamSize stream size dimensions, in pixels
- *
- * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
- */
- public static List<Rect> getAvailablePreviewZoomCropRectangles(Camera.Parameters params,
- Rect activeArray, Size previewSize) {
- checkNotNull(params, "params must not be null");
- checkNotNull(activeArray, "activeArray must not be null");
- checkNotNull(previewSize, "previewSize must not be null");
-
- return getAvailableCropRectangles(params, activeArray, previewSize);
- }
-
- /**
- * Get the available 'crop' (zoom) rectangles for this camera.
- *
- * <p>When zoom is supported, this will return a list of {@code 1 + #getMaxZoom} size,
- * where each crop rectangle corresponds to a zoom ratio (and is centered at the middle).</p>
- *
- * <p>Each crop rectangle is changed to have the same aspect ratio as {@code streamSize},
- * by shrinking the rectangle if necessary.</p>
- *
- * <p>To get the reported crop region when applying a zoom to the sensor, use {@code streamSize}
- * = {@code activeArray size}.</p>
- *
- * @param params non-{@code null} camera api1 parameters
- * @param activeArray active array dimensions, in sensor space
- * @param streamSize stream size dimensions, in pixels
- *
- * @return a list of available zoom rectangles, sorted from least zoomed to most zoomed
- */
- private static List<Rect> getAvailableCropRectangles(Camera.Parameters params,
- Rect activeArray, Size streamSize) {
- checkNotNull(params, "params must not be null");
- checkNotNull(activeArray, "activeArray must not be null");
- checkNotNull(streamSize, "streamSize must not be null");
-
- // TODO: change all uses of Rect activeArray to Size activeArray,
- // since we want the crop to be active-array relative, not pixel-array relative
-
- Rect unzoomedStreamCrop = getPreviewCropRectangleUnzoomed(activeArray, streamSize);
-
- if (!params.isZoomSupported()) {
- // Trivial case: No zoom -> only support the full size as the crop region
- return new ArrayList<>(Arrays.asList(unzoomedStreamCrop));
- }
-
- List<Rect> zoomCropRectangles = new ArrayList<>(params.getMaxZoom() + 1);
- Matrix scaleMatrix = new Matrix();
- RectF scaledRect = new RectF();
-
- for (int zoom : params.getZoomRatios()) {
- float shrinkRatio = ZOOM_RATIO_MULTIPLIER * 1.0f / zoom; // normalize to 1.0 and smaller
-
- // set scaledRect to unzoomedStreamCrop
- ParamsUtils.convertRectF(unzoomedStreamCrop, /*out*/scaledRect);
-
- scaleMatrix.setScale(
- shrinkRatio, shrinkRatio,
- activeArray.exactCenterX(),
- activeArray.exactCenterY());
-
- scaleMatrix.mapRect(scaledRect);
-
- Rect intRect = ParamsUtils.createRect(scaledRect);
-
- // Round the rect corners towards the nearest integer values
- zoomCropRectangles.add(intRect);
- }
-
- return zoomCropRectangles;
- }
-
- /**
- * Get the largest possible zoom ratio (normalized to {@code 1.0f} and higher)
- * that the camera can support.
- *
- * <p>If the camera does not support zoom, it always returns {@code 1.0f}.</p>
- *
- * @param params non-{@code null} camera api1 parameters
- * @return normalized max zoom ratio, at least {@code 1.0f}
- */
- public static float getMaxZoomRatio(Camera.Parameters params) {
- if (!params.isZoomSupported()) {
- return 1.0f; // no zoom
- }
-
- List<Integer> zoomRatios = params.getZoomRatios(); // sorted smallest->largest
- int zoom = zoomRatios.get(zoomRatios.size() - 1); // largest zoom ratio
- float zoomRatio = zoom * 1.0f / ZOOM_RATIO_MULTIPLIER; // normalize to 1.0 and smaller
-
- return zoomRatio;
- }
-
- /**
- * Returns the component-wise zoom ratio (each greater or equal than {@code 1.0});
- * largest values means more zoom.
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param cropSize size of the crop/zoom
- *
- * @return {@link SizeF} with width/height being the component-wise zoom ratio
- *
- * @throws NullPointerException if any of the args were {@code null}
- * @throws IllegalArgumentException if any component of {@code cropSize} was {@code 0}
- */
- private static SizeF getZoomRatio(Size activeArraySize, Size cropSize) {
- checkNotNull(activeArraySize, "activeArraySize must not be null");
- checkNotNull(cropSize, "cropSize must not be null");
- checkArgumentPositive(cropSize.getWidth(), "cropSize.width must be positive");
- checkArgumentPositive(cropSize.getHeight(), "cropSize.height must be positive");
-
- float zoomRatioWidth = activeArraySize.getWidth() * 1.0f / cropSize.getWidth();
- float zoomRatioHeight = activeArraySize.getHeight() * 1.0f / cropSize.getHeight();
-
- return new SizeF(zoomRatioWidth, zoomRatioHeight);
- }
-
- /**
- * Convert the user-specified crop region/zoom into zoom data; which can be used
- * to set the parameters to a specific zoom index, or to report back to the user what
- * the actual zoom was, or for other calculations requiring the current preview crop region.
- *
- * <p>None of the parameters are mutated.<p>
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param cropRegion the user-specified crop region
- * @param zoomRatio the user-specified zoom ratio
- * @param previewSize the current preview size (in pixels)
- * @param params the current camera parameters (not mutated)
- *
- * @return the zoom index, and the effective/reported crop regions (relative to active array)
- */
- public static ZoomData convertToLegacyZoom(Rect activeArraySize, Rect
- cropRegion, Float zoomRatio, Size previewSize, Camera.Parameters params) {
- final float FLOAT_EQUAL_THRESHOLD = 0.0001f;
- if (zoomRatio != null &&
- Math.abs(1.0f - zoomRatio) > FLOAT_EQUAL_THRESHOLD) {
- // User uses CONTROL_ZOOM_RATIO to control zoom
- return convertZoomRatio(activeArraySize, zoomRatio, previewSize, params);
- }
-
- return convertScalerCropRegion(activeArraySize, cropRegion, previewSize, params);
- }
-
- /**
- * Convert the user-specified zoom ratio into zoom data; which can be used
- * to set the parameters to a specific zoom index, or to report back to the user what the
- * actual zoom was, or for other calculations requiring the current preview crop region.
- *
- * <p>None of the parameters are mutated.</p>
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param zoomRatio the current zoom ratio
- * @param previewSize the current preview size (in pixels)
- * @param params the current camera parameters (not mutated)
- *
- * @return the zoom index, and the effective/reported crop regions (relative to active array)
- */
- public static ZoomData convertZoomRatio(Rect activeArraySize, float zoomRatio,
- Size previewSize, Camera.Parameters params) {
- if (DEBUG) {
- Log.v(TAG, "convertZoomRatio - user zoom ratio was " + zoomRatio);
- }
-
- List<Rect> availableReportedCropRegions =
- getAvailableZoomCropRectangles(params, activeArraySize);
- List<Rect> availablePreviewCropRegions =
- getAvailablePreviewZoomCropRectangles(params, activeArraySize, previewSize);
- if (availableReportedCropRegions.size() != availablePreviewCropRegions.size()) {
- throw new AssertionError("available reported/preview crop region size mismatch");
- }
-
- // Find the best matched legacy zoom ratio for the requested camera2 zoom ratio.
- int bestZoomIndex = 0;
- Rect reportedCropRegion = new Rect(availableReportedCropRegions.get(0));
- Rect previewCropRegion = new Rect(availablePreviewCropRegions.get(0));
- float reportedZoomRatio = 1.0f;
- if (params.isZoomSupported()) {
- List<Integer> zoomRatios = params.getZoomRatios();
- for (int i = 1; i < zoomRatios.size(); i++) {
- if (zoomRatio * ZOOM_RATIO_MULTIPLIER >= zoomRatios.get(i)) {
- bestZoomIndex = i;
- reportedCropRegion = availableReportedCropRegions.get(i);
- previewCropRegion = availablePreviewCropRegions.get(i);
- reportedZoomRatio = zoomRatios.get(i);
- } else {
- break;
- }
- }
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertZoomRatio - zoom calculated to: " +
- "zoomIndex = " + bestZoomIndex +
- ", reported crop region = " + reportedCropRegion +
- ", preview crop region = " + previewCropRegion +
- ", reported zoom ratio = " + reportedZoomRatio);
- }
-
- return new ZoomData(bestZoomIndex, reportedCropRegion,
- previewCropRegion, reportedZoomRatio);
- }
-
- /**
- * Convert the user-specified crop region into zoom data; which can be used
- * to set the parameters to a specific zoom index, or to report back to the user what the
- * actual zoom was, or for other calculations requiring the current preview crop region.
- *
- * <p>None of the parameters are mutated.</p>
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param cropRegion the user-specified crop region
- * @param previewSize the current preview size (in pixels)
- * @param params the current camera parameters (not mutated)
- *
- * @return the zoom index, and the effective/reported crop regions (relative to active array)
- */
- public static ZoomData convertScalerCropRegion(Rect activeArraySize, Rect
- cropRegion, Size previewSize, Camera.Parameters params) {
- Rect activeArraySizeOnly = new Rect(
- /*left*/0, /*top*/0,
- activeArraySize.width(), activeArraySize.height());
-
- Rect userCropRegion = cropRegion;
-
- if (userCropRegion == null) {
- userCropRegion = activeArraySizeOnly;
- }
-
- if (DEBUG) {
- Log.v(TAG, "convertScalerCropRegion - user crop region was " + userCropRegion);
- }
-
- final Rect reportedCropRegion = new Rect();
- final Rect previewCropRegion = new Rect();
- final int zoomIdx = ParameterUtils.getClosestAvailableZoomCrop(params, activeArraySizeOnly,
- previewSize, userCropRegion,
- /*out*/reportedCropRegion, /*out*/previewCropRegion);
- final float reportedZoomRatio = 1.0f;
-
- if (DEBUG) {
- Log.v(TAG, "convertScalerCropRegion - zoom calculated to: " +
- "zoomIndex = " + zoomIdx +
- ", reported crop region = " + reportedCropRegion +
- ", preview crop region = " + previewCropRegion +
- ", reported zoom ratio = " + reportedZoomRatio);
- }
-
- return new ZoomData(zoomIdx, previewCropRegion, reportedCropRegion, reportedZoomRatio);
- }
-
- /**
- * Calculate the actual/effective/reported normalized rectangle data from a metering
- * rectangle.
- *
- * <p>If any of the rectangles are out-of-range of their intended bounding box,
- * the {@link #RECTANGLE_EMPTY empty rectangle} is substituted instead
- * (with a weight of {@code 0}).</p>
- *
- * <p>The metering rectangle is bound by the crop region (effective/reported respectively).
- * The metering {@link Camera.Area area} is bound by {@code [-1000, 1000]}.</p>
- *
- * <p>No parameters are mutated; returns the new metering data.</p>
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param meteringRect the user-specified metering rectangle
- * @param zoomData the calculated zoom data corresponding to this request
- *
- * @return the metering area, the reported/effective metering rectangles
- */
- public static MeteringData convertMeteringRectangleToLegacy(
- Rect activeArray, MeteringRectangle meteringRect, ZoomData zoomData) {
- Rect previewCrop = zoomData.previewCrop;
-
- float scaleW = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
- previewCrop.width();
- float scaleH = (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN) * 1.0f /
- previewCrop.height();
-
- Matrix transform = new Matrix();
- // Move the preview crop so that top,left is at (0,0), otherwise after scaling
- // the corner bounds will be outside of [-1000, 1000]
- transform.setTranslate(-previewCrop.left, -previewCrop.top);
- // Scale into [0, 2000] range about the center of the preview
- transform.postScale(scaleW, scaleH);
- // Move so that top left of a typical rect is at [-1000, -1000]
- transform.postTranslate(/*dx*/NORMALIZED_RECTANGLE_MIN, /*dy*/NORMALIZED_RECTANGLE_MIN);
-
- /*
- * Calculate the preview metering region (effective), and the camera1 api
- * normalized metering region.
- */
- Rect normalizedRegionUnbounded = ParamsUtils.mapRect(transform, meteringRect.getRect());
-
- /*
- * Try to intersect normalized area with [-1000, 1000] rectangle; otherwise
- * it's completely out of range
- */
- Rect normalizedIntersected = new Rect(normalizedRegionUnbounded);
-
- Camera.Area meteringArea;
- if (!normalizedIntersected.intersect(NORMALIZED_RECTANGLE_DEFAULT)) {
- Log.w(TAG,
- "convertMeteringRectangleToLegacy - metering rectangle too small, " +
- "no metering will be done");
- normalizedIntersected.set(RECTANGLE_EMPTY);
- meteringArea = new Camera.Area(RECTANGLE_EMPTY,
- MeteringRectangle.METERING_WEIGHT_DONT_CARE);
- } else {
- meteringArea = new Camera.Area(normalizedIntersected,
- meteringRect.getMeteringWeight());
- }
-
- /*
- * Calculate effective preview metering region
- */
- Rect previewMetering = meteringRect.getRect();
- if (!previewMetering.intersect(previewCrop)) {
- previewMetering.set(RECTANGLE_EMPTY);
- }
-
- /*
- * Calculate effective reported metering region
- * - Transform the calculated metering area back into active array space
- * - Clip it to be a subset of the reported crop region
- */
- Rect reportedMetering;
- {
- Camera.Area normalizedAreaUnbounded = new Camera.Area(
- normalizedRegionUnbounded, meteringRect.getMeteringWeight());
- WeightedRectangle reportedMeteringRect = convertCameraAreaToActiveArrayRectangle(
- activeArray, zoomData, normalizedAreaUnbounded, /*usePreviewCrop*/false);
- reportedMetering = reportedMeteringRect.rect;
- }
-
- if (DEBUG) {
- Log.v(TAG, String.format(
- "convertMeteringRectangleToLegacy - activeArray = %s, meteringRect = %s, " +
- "previewCrop = %s, meteringArea = %s, previewMetering = %s, " +
- "reportedMetering = %s, normalizedRegionUnbounded = %s",
- activeArray, meteringRect,
- previewCrop, stringFromArea(meteringArea), previewMetering,
- reportedMetering, normalizedRegionUnbounded));
- }
-
- return new MeteringData(meteringArea, previewMetering, reportedMetering);
- }
-
- /**
- * Convert the normalized camera area from [-1000, 1000] coordinate space
- * into the active array-based coordinate space.
- *
- * <p>Values out of range are clipped to be within the resulting (reported) crop
- * region. It is possible to have values larger than the preview crop.</p>
- *
- * <p>Weights out of range of [0, 1000] are clipped to be within the range.</p>
- *
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param zoomData the calculated zoom data corresponding to this request
- * @param area the normalized camera area
- *
- * @return the weighed rectangle in active array coordinate space, with the weight
- */
- public static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
- Rect activeArray, ZoomData zoomData, Camera.Area area) {
- return convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, area,
- /*usePreviewCrop*/true);
- }
-
- /**
- * Convert an api1 face into an active-array based api2 face.
- *
- * <p>Out-of-ranges scores and ids will be clipped to be within range (with a warning).</p>
- *
- * @param face a non-{@code null} api1 face
- * @param activeArraySize active array size of the sensor (e.g. max jpeg size)
- * @param zoomData the calculated zoom data corresponding to this request
- *
- * @return a non-{@code null} api2 face
- *
- * @throws NullPointerException if the {@code face} was {@code null}
- */
- public static Face convertFaceFromLegacy(Camera.Face face, Rect activeArray,
- ZoomData zoomData) {
- checkNotNull(face, "face must not be null");
-
- Face api2Face;
-
- Camera.Area fakeArea = new Camera.Area(face.rect, /*weight*/1);
-
- WeightedRectangle faceRect =
- convertCameraAreaToActiveArrayRectangle(activeArray, zoomData, fakeArea);
-
- Point leftEye = face.leftEye, rightEye = face.rightEye, mouth = face.mouth;
- if (leftEye != null && rightEye != null && mouth != null && leftEye.x != -2000 &&
- leftEye.y != -2000 && rightEye.x != -2000 && rightEye.y != -2000 &&
- mouth.x != -2000 && mouth.y != -2000) {
- leftEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
- leftEye, /*usePreviewCrop*/true);
- rightEye = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
- leftEye, /*usePreviewCrop*/true);
- mouth = convertCameraPointToActiveArrayPoint(activeArray, zoomData,
- leftEye, /*usePreviewCrop*/true);
-
- api2Face = faceRect.toFace(face.id, leftEye, rightEye, mouth);
- } else {
- api2Face = faceRect.toFace();
- }
-
- return api2Face;
- }
-
- private static Point convertCameraPointToActiveArrayPoint(
- Rect activeArray, ZoomData zoomData, Point point, boolean usePreviewCrop) {
- Rect pointedRect = new Rect(point.x, point.y, point.x, point.y);
- Camera.Area pointedArea = new Area(pointedRect, /*weight*/1);
-
- WeightedRectangle adjustedRect =
- convertCameraAreaToActiveArrayRectangle(activeArray,
- zoomData, pointedArea, usePreviewCrop);
-
- Point transformedPoint = new Point(adjustedRect.rect.left, adjustedRect.rect.top);
-
- return transformedPoint;
- }
-
- private static WeightedRectangle convertCameraAreaToActiveArrayRectangle(
- Rect activeArray, ZoomData zoomData, Camera.Area area, boolean usePreviewCrop) {
- Rect previewCrop = zoomData.previewCrop;
- Rect reportedCrop = zoomData.reportedCrop;
-
- float scaleW = previewCrop.width() * 1.0f /
- (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
- float scaleH = previewCrop.height() * 1.0f /
- (NORMALIZED_RECTANGLE_MAX - NORMALIZED_RECTANGLE_MIN);
-
- /*
- * Calculate the reported metering region from the non-intersected normalized region
- * by scaling and translating back into active array-relative coordinates.
- */
- Matrix transform = new Matrix();
-
- // Move top left from (-1000, -1000) to (0, 0)
- transform.setTranslate(/*dx*/NORMALIZED_RECTANGLE_MAX, /*dy*/NORMALIZED_RECTANGLE_MAX);
-
- // Scale from [0, 2000] back into the preview rectangle
- transform.postScale(scaleW, scaleH);
-
- // Move the rect so that the [-1000,-1000] point ends up at the preview [left, top]
- transform.postTranslate(previewCrop.left, previewCrop.top);
-
- Rect cropToIntersectAgainst = usePreviewCrop ? previewCrop : reportedCrop;
-
- // Now apply the transformation backwards to get the reported metering region
- Rect reportedMetering = ParamsUtils.mapRect(transform, area.rect);
- // Intersect it with the crop region, to avoid reporting out-of-bounds
- // metering regions
- if (!reportedMetering.intersect(cropToIntersectAgainst)) {
- reportedMetering.set(RECTANGLE_EMPTY);
- }
-
- int weight = area.weight;
- if (weight < MeteringRectangle.METERING_WEIGHT_MIN) {
- Log.w(TAG,
- "convertCameraAreaToMeteringRectangle - rectangle "
- + stringFromArea(area) + " has too small weight, clip to 0");
- weight = 0;
- }
-
- return new WeightedRectangle(reportedMetering, area.weight);
- }
-
-
- private ParameterUtils() {
- throw new AssertionError();
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/PerfMeasurement.java b/core/java/android/hardware/camera2/legacy/PerfMeasurement.java
deleted file mode 100644
index 53278c7e4f97..000000000000
--- a/core/java/android/hardware/camera2/legacy/PerfMeasurement.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.BufferedWriter;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * GPU and CPU performance measurement for the legacy implementation.
- *
- * <p>Measures CPU and GPU processing duration for a set of operations, and dumps
- * the results into a file.</p>
- *
- * <p>Rough usage:
- * <pre>
- * {@code
- * <set up workload>
- * <start long-running workload>
- * mPerfMeasurement.startTimer();
- * ...render a frame...
- * mPerfMeasurement.stopTimer();
- * <end workload>
- * mPerfMeasurement.dumpPerformanceData("/sdcard/my_data.txt");
- * }
- * </pre>
- * </p>
- *
- * <p>All calls to this object must be made within the same thread, and the same GL context.
- * PerfMeasurement cannot be used outside of a GL context. The only exception is
- * dumpPerformanceData, which can be called outside of a valid GL context.</p>
- */
-class PerfMeasurement {
- private static final String TAG = "PerfMeasurement";
-
- public static final int DEFAULT_MAX_QUERIES = 3;
-
- private final long mNativeContext;
-
- private int mCompletedQueryCount = 0;
-
- /**
- * Values for completed measurements
- */
- private ArrayList<Long> mCollectedGpuDurations = new ArrayList<>();
- private ArrayList<Long> mCollectedCpuDurations = new ArrayList<>();
- private ArrayList<Long> mCollectedTimestamps = new ArrayList<>();
-
- /**
- * Values for in-progress measurements (waiting for async GPU results)
- */
- private Queue<Long> mTimestampQueue = new LinkedList<>();
- private Queue<Long> mCpuDurationsQueue = new LinkedList<>();
-
- private long mStartTimeNs;
-
- /**
- * The value returned by {@link #nativeGetNextGlDuration} if no new timing
- * measurement is available since the last call.
- */
- private static final long NO_DURATION_YET = -1l;
-
- /**
- * The value returned by {@link #nativeGetNextGlDuration} if timing failed for
- * the next timing interval
- */
- private static final long FAILED_TIMING = -2l;
-
- /**
- * Create a performance measurement object with a maximum of {@value #DEFAULT_MAX_QUERIES}
- * in-progess queries.
- */
- public PerfMeasurement() {
- mNativeContext = nativeCreateContext(DEFAULT_MAX_QUERIES);
- }
-
- /**
- * Create a performance measurement object with maxQueries as the maximum number of
- * in-progress queries.
- *
- * @param maxQueries maximum in-progress queries, must be larger than 0.
- * @throws IllegalArgumentException if maxQueries is less than 1.
- */
- public PerfMeasurement(int maxQueries) {
- if (maxQueries < 1) throw new IllegalArgumentException("maxQueries is less than 1");
- mNativeContext = nativeCreateContext(maxQueries);
- }
-
- /**
- * Returns true if the Gl timing methods will work, false otherwise.
- *
- * <p>Must be called within a valid GL context.</p>
- */
- public static boolean isGlTimingSupported() {
- return nativeQuerySupport();
- }
-
- /**
- * Dump collected data to file, and clear the stored data.
- *
- * <p>
- * Format is a simple csv-like text file with a header,
- * followed by a 3-column list of values in nanoseconds:
- * <pre>
- * timestamp gpu_duration cpu_duration
- * <long> <long> <long>
- * <long> <long> <long>
- * <long> <long> <long>
- * ....
- * </pre>
- * </p>
- */
- public void dumpPerformanceData(String path) {
- try (BufferedWriter dump = new BufferedWriter(new FileWriter(path))) {
- dump.write("timestamp gpu_duration cpu_duration\n");
- for (int i = 0; i < mCollectedGpuDurations.size(); i++) {
- dump.write(String.format("%d %d %d\n",
- mCollectedTimestamps.get(i),
- mCollectedGpuDurations.get(i),
- mCollectedCpuDurations.get(i)));
- }
- mCollectedTimestamps.clear();
- mCollectedGpuDurations.clear();
- mCollectedCpuDurations.clear();
- } catch (IOException e) {
- Log.e(TAG, "Error writing data dump to " + path + ":" + e);
- }
- }
-
- /**
- * Start a GPU/CPU timing measurement.
- *
- * <p>Call before starting a rendering pass. Only one timing measurement can be active at once,
- * so {@link #stopTimer} must be called before the next call to this method.</p>
- *
- * @throws IllegalStateException if the maximum number of queries are in progress already,
- * or the method is called multiple times in a row, or there is
- * a GPU error.
- */
- public void startTimer() {
- nativeStartGlTimer(mNativeContext);
- mStartTimeNs = SystemClock.elapsedRealtimeNanos();
- }
-
- /**
- * Finish a GPU/CPU timing measurement.
- *
- * <p>Call after finishing all the drawing for a rendering pass. Only one timing measurement can
- * be active at once, so {@link #startTimer} must be called before the next call to this
- * method.</p>
- *
- * @throws IllegalStateException if no GL timer is currently started, or there is a GPU
- * error.
- */
- public void stopTimer() {
- // Complete CPU timing
- long endTimeNs = SystemClock.elapsedRealtimeNanos();
- mCpuDurationsQueue.add(endTimeNs - mStartTimeNs);
- // Complete GL timing
- nativeStopGlTimer(mNativeContext);
-
- // Poll to see if GL timing results have arrived; if so
- // store the results for a frame
- long duration = getNextGlDuration();
- if (duration > 0) {
- mCollectedGpuDurations.add(duration);
- mCollectedTimestamps.add(mTimestampQueue.isEmpty() ?
- NO_DURATION_YET : mTimestampQueue.poll());
- mCollectedCpuDurations.add(mCpuDurationsQueue.isEmpty() ?
- NO_DURATION_YET : mCpuDurationsQueue.poll());
- }
- if (duration == FAILED_TIMING) {
- // Discard timestamp and CPU measurement since GPU measurement failed
- if (!mTimestampQueue.isEmpty()) {
- mTimestampQueue.poll();
- }
- if (!mCpuDurationsQueue.isEmpty()) {
- mCpuDurationsQueue.poll();
- }
- }
- }
-
- /**
- * Add a timestamp to a timing measurement. These are queued up and matched to completed
- * workload measurements as they become available.
- */
- public void addTimestamp(long timestamp) {
- mTimestampQueue.add(timestamp);
- }
-
- /**
- * Get the next available GPU timing measurement.
- *
- * <p>Since the GPU works asynchronously, the results of a single start/stopGlTimer measurement
- * will only be available some time after the {@link #stopTimer} call is made. Poll this method
- * until the result becomes available. If multiple start/endTimer measurements are made in a
- * row, the results will be available in FIFO order.</p>
- *
- * @return The measured duration of the GPU workload for the next pending query, or
- * {@link #NO_DURATION_YET} if no queries are pending or the next pending query has not
- * yet finished, or {@link #FAILED_TIMING} if the GPU was unable to complete the
- * measurement.
- *
- * @throws IllegalStateException If there is a GPU error.
- *
- */
- private long getNextGlDuration() {
- long duration = nativeGetNextGlDuration(mNativeContext);
- if (duration > 0) {
- mCompletedQueryCount++;
- }
- return duration;
- }
-
- /**
- * Returns the number of measurements so far that returned a valid duration
- * measurement.
- */
- public int getCompletedQueryCount() {
- return mCompletedQueryCount;
- }
-
- @Override
- protected void finalize() {
- nativeDeleteContext(mNativeContext);
- }
-
- /**
- * Create a native performance measurement context.
- *
- * @param maxQueryCount maximum in-progress queries; must be >= 1.
- */
- private static native long nativeCreateContext(int maxQueryCount);
-
- /**
- * Delete the native context.
- *
- * <p>Not safe to call more than once.</p>
- */
- private static native void nativeDeleteContext(long contextHandle);
-
- /**
- * Query whether the relevant Gl extensions are available for Gl timing
- */
- private static native boolean nativeQuerySupport();
-
- /**
- * Start a GL timing section.
- *
- * <p>All GL commands between this method and the next {@link #nativeEndGlTimer} will be
- * included in the timing.</p>
- *
- * <p>Must be called from the same thread as calls to {@link #nativeEndGlTimer} and
- * {@link #nativeGetNextGlDuration}.</p>
- *
- * @throws IllegalStateException if a GL error occurs or start is called repeatedly.
- */
- protected static native void nativeStartGlTimer(long contextHandle);
-
- /**
- * Finish a GL timing section.
- *
- * <p>Some time after this call returns, the time the GPU took to
- * execute all work submitted between the latest {@link #nativeStartGlTimer} and
- * this call, will become available from calling {@link #nativeGetNextGlDuration}.</p>
- *
- * <p>Must be called from the same thread as calls to {@link #nativeStartGlTimer} and
- * {@link #nativeGetNextGlDuration}.</p>
- *
- * @throws IllegalStateException if a GL error occurs or stop is called before start
- */
- protected static native void nativeStopGlTimer(long contextHandle);
-
- /**
- * Get the next available GL duration measurement, in nanoseconds.
- *
- * <p>Must be called from the same thread as calls to {@link #nativeStartGlTimer} and
- * {@link #nativeEndGlTimer}.</p>
- *
- * @return the next GL duration measurement, or {@link #NO_DURATION_YET} if
- * no new measurement is available, or {@link #FAILED_TIMING} if timing
- * failed for the next duration measurement.
- * @throws IllegalStateException if a GL error occurs
- */
- protected static native long nativeGetNextGlDuration(long contextHandle);
-
-
-}
diff --git a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
deleted file mode 100644
index e19ebf2d616b..000000000000
--- a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.MessageQueue;
-
-public class RequestHandlerThread extends HandlerThread {
-
- /**
- * Ensure that the MessageQueue's idle handler gets run by poking the message queue;
- * normally if the message queue is already idle, the idle handler won't get invoked.
- *
- * <p>Users of this handler thread should ignore this message.</p>
- */
- public final static int MSG_POKE_IDLE_HANDLER = -1;
-
- private final ConditionVariable mStarted = new ConditionVariable(false);
- private final ConditionVariable mIdle = new ConditionVariable(true);
- private Handler.Callback mCallback;
- private volatile Handler mHandler;
-
- public RequestHandlerThread(String name, Handler.Callback callback) {
- super(name, Thread.MAX_PRIORITY);
- mCallback = callback;
- }
-
- @Override
- protected void onLooperPrepared() {
- mHandler = new Handler(getLooper(), mCallback);
- mStarted.open();
- }
-
- // Blocks until thread has started
- public void waitUntilStarted() {
- mStarted.block();
- }
-
- // May return null if the handler is not set up yet.
- public Handler getHandler() {
- return mHandler;
- }
-
- // Blocks until thread has started
- public Handler waitAndGetHandler() {
- waitUntilStarted();
- return getHandler();
- }
-
- // Atomic multi-type message existence check
- public boolean hasAnyMessages(int[] what) {
- synchronized (mHandler.getLooper().getQueue()) {
- for (int i : what) {
- if (mHandler.hasMessages(i)) {
- return true;
- }
- }
- }
- return false;
- }
-
- // Atomic multi-type message remove
- public void removeMessages(int[] what) {
- synchronized (mHandler.getLooper().getQueue()) {
- for (int i : what) {
- mHandler.removeMessages(i);
- }
- }
- }
-
- private final MessageQueue.IdleHandler mIdleHandler = new MessageQueue.IdleHandler() {
- @Override
- public boolean queueIdle() {
- mIdle.open();
- return false;
- }
- };
-
- // Blocks until thread is idling
- public void waitUntilIdle() {
- Handler handler = waitAndGetHandler();
- MessageQueue queue = handler.getLooper().getQueue();
- if (queue.isIdle()) {
- return;
- }
- mIdle.close();
- queue.addIdleHandler(mIdleHandler);
- // Ensure that the idle handler gets run even if the looper already went idle
- handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
- if (queue.isIdle()) {
- return;
- }
- mIdle.block();
- }
-
-}
diff --git a/core/java/android/hardware/camera2/legacy/RequestHolder.java b/core/java/android/hardware/camera2/legacy/RequestHolder.java
deleted file mode 100644
index 98b761b8a04f..000000000000
--- a/core/java/android/hardware/camera2/legacy/RequestHolder.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.camera2.CaptureRequest;
-import android.util.Log;
-import android.view.Surface;
-
-import java.util.Collection;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Semi-immutable container for a single capture request and associated information,
- * the only mutable characteristic of this container is whether or not is has been
- * marked as "failed" using {@code #failRequest}.
- */
-public class RequestHolder {
- private static final String TAG = "RequestHolder";
-
- private final boolean mRepeating;
- private final CaptureRequest mRequest;
- private final int mRequestId;
- private final int mSubsequeceId;
- private final long mFrameNumber;
- private final int mNumJpegTargets;
- private final int mNumPreviewTargets;
- private volatile boolean mFailed = false;
- private boolean mOutputAbandoned = false;
-
- private final Collection<Long> mJpegSurfaceIds;
-
- /**
- * A builder class for {@link RequestHolder} objects.
- *
- * <p>
- * This allows per-request queries to be cached for repeating {@link CaptureRequest} objects.
- * </p>
- */
- public final static class Builder {
- private final int mRequestId;
- private final int mSubsequenceId;
- private final CaptureRequest mRequest;
- private final boolean mRepeating;
- private final int mNumJpegTargets;
- private final int mNumPreviewTargets;
- private final Collection<Long> mJpegSurfaceIds;
-
- /**
- * Construct a new {@link Builder} to generate {@link RequestHolder} objects.
- *
- * @param requestId the ID to set in {@link RequestHolder} objects.
- * @param subsequenceId the sequence ID to set in {@link RequestHolder} objects.
- * @param request the original {@link CaptureRequest} to set in {@link RequestHolder}
- * objects.
- * @param repeating {@code true} if the request is repeating.
- */
- public Builder(int requestId, int subsequenceId, CaptureRequest request,
- boolean repeating, Collection<Long> jpegSurfaceIds) {
- checkNotNull(request, "request must not be null");
- mRequestId = requestId;
- mSubsequenceId = subsequenceId;
- mRequest = request;
- mRepeating = repeating;
- mJpegSurfaceIds = jpegSurfaceIds;
- mNumJpegTargets = numJpegTargets(mRequest);
- mNumPreviewTargets = numPreviewTargets(mRequest);
- }
-
- /**
- * Returns true if the given surface requires jpeg buffers.
- *
- * @param s a {@link android.view.Surface} to check.
- * @return true if the surface requires a jpeg buffer.
- */
- private boolean jpegType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
- }
-
- /**
- * Returns true if the given surface requires non-jpeg buffer types.
- *
- * <p>
- * "Jpeg buffer" refers to the buffers returned in the jpeg
- * {@link android.hardware.Camera.PictureCallback}. Non-jpeg buffers are created using a tee
- * of the preview stream drawn to the surface
- * set via {@link android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)} or
- * equivalent methods.
- * </p>
- * @param s a {@link android.view.Surface} to check.
- * @return true if the surface requires a non-jpeg buffer type.
- */
- private boolean previewType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- return !jpegType(s);
- }
-
- /**
- * Returns the number of surfaces targeted by the request that require jpeg buffers.
- */
- private int numJpegTargets(CaptureRequest request) {
- int count = 0;
- for (Surface s : request.getTargets()) {
- try {
- if (jpegType(s)) {
- ++count;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.d(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return count;
- }
-
- /**
- * Returns the number of surfaces targeted by the request that require non-jpeg buffers.
- */
- private int numPreviewTargets(CaptureRequest request) {
- int count = 0;
- for (Surface s : request.getTargets()) {
- try {
- if (previewType(s)) {
- ++count;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.d(TAG, "Surface abandoned, skipping...", e);
- }
- }
- return count;
- }
-
- /**
- * Build a new {@link RequestHolder} using with parameters generated from this
- * {@link Builder}.
- *
- * @param frameNumber the {@code framenumber} to generate in the {@link RequestHolder}.
- * @return a {@link RequestHolder} constructed with the {@link Builder}'s parameters.
- */
- public RequestHolder build(long frameNumber) {
- return new RequestHolder(mRequestId, mSubsequenceId, mRequest, mRepeating, frameNumber,
- mNumJpegTargets, mNumPreviewTargets, mJpegSurfaceIds);
- }
- }
-
- private RequestHolder(int requestId, int subsequenceId, CaptureRequest request,
- boolean repeating, long frameNumber, int numJpegTargets,
- int numPreviewTargets, Collection<Long> jpegSurfaceIds) {
- mRepeating = repeating;
- mRequest = request;
- mRequestId = requestId;
- mSubsequeceId = subsequenceId;
- mFrameNumber = frameNumber;
- mNumJpegTargets = numJpegTargets;
- mNumPreviewTargets = numPreviewTargets;
- mJpegSurfaceIds = jpegSurfaceIds;
- }
-
- /**
- * Return the request id for the contained {@link CaptureRequest}.
- */
- public int getRequestId() {
- return mRequestId;
- }
-
- /**
- * Returns true if the contained request is repeating.
- */
- public boolean isRepeating() {
- return mRepeating;
- }
-
- /**
- * Return the subsequence id for this request.
- */
- public int getSubsequeceId() {
- return mSubsequeceId;
- }
-
- /**
- * Returns the frame number for this request.
- */
- public long getFrameNumber() {
- return mFrameNumber;
- }
-
- /**
- * Returns the contained request.
- */
- public CaptureRequest getRequest() {
- return mRequest;
- }
-
- /**
- * Returns a read-only collection of the surfaces targeted by the contained request.
- */
- public Collection<Surface> getHolderTargets() {
- return getRequest().getTargets();
- }
-
- /**
- * Returns true if any of the surfaces targeted by the contained request require jpeg buffers.
- */
- public boolean hasJpegTargets() {
- return mNumJpegTargets > 0;
- }
-
- /**
- * Returns true if any of the surfaces targeted by the contained request require a
- * non-jpeg buffer type.
- */
- public boolean hasPreviewTargets(){
- return mNumPreviewTargets > 0;
- }
-
- /**
- * Return the number of jpeg-type surfaces targeted by this request.
- */
- public int numJpegTargets() {
- return mNumJpegTargets;
- }
-
- /**
- * Return the number of non-jpeg-type surfaces targeted by this request.
- */
- public int numPreviewTargets() {
- return mNumPreviewTargets;
- }
-
- /**
- * Returns true if the given surface requires jpeg buffers.
- *
- * @param s a {@link android.view.Surface} to check.
- * @return true if the surface requires a jpeg buffer.
- */
- public boolean jpegType(Surface s)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- return LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds);
- }
-
- /**
- * Mark this request as failed.
- */
- public void failRequest() {
- Log.w(TAG, "Capture failed for request: " + getRequestId());
- mFailed = true;
- }
-
- /**
- * Return {@code true} if this request failed.
- */
- public boolean requestFailed() {
- return mFailed;
- }
-
- /**
- * Mark at least one of this request's output surfaces is abandoned.
- */
- public void setOutputAbandoned() {
- mOutputAbandoned = true;
- }
-
- /**
- * Return if any of this request's output surface is abandoned.
- */
- public boolean isOutputAbandoned() {
- return mOutputAbandoned;
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
deleted file mode 100644
index fb444022c6db..000000000000
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.legacy;
-
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.utils.SubmitInfo;
-import android.util.Log;
-
-import java.util.ArrayDeque;
-import java.util.List;
-
-/**
- * A queue of bursts of requests.
- *
- * <p>This queue maintains the count of frames that have been produced, and is thread safe.</p>
- */
-public class RequestQueue {
- private static final String TAG = "RequestQueue";
-
- public static final long INVALID_FRAME = -1;
-
- private BurstHolder mRepeatingRequest = null;
- private final ArrayDeque<BurstHolder> mRequestQueue = new ArrayDeque<BurstHolder>();
-
- private long mCurrentFrameNumber = 0;
- private long mCurrentRepeatingFrameNumber = INVALID_FRAME;
- private int mCurrentRequestId = 0;
- private final List<Long> mJpegSurfaceIds;
-
- public final class RequestQueueEntry {
- private final BurstHolder mBurstHolder;
- private final Long mFrameNumber;
- private final boolean mQueueEmpty;
-
- public BurstHolder getBurstHolder() {
- return mBurstHolder;
- }
- public Long getFrameNumber() {
- return mFrameNumber;
- }
- public boolean isQueueEmpty() {
- return mQueueEmpty;
- }
-
- public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) {
- mBurstHolder = burstHolder;
- mFrameNumber = frameNumber;
- mQueueEmpty = queueEmpty;
- }
- }
-
- public RequestQueue(List<Long> jpegSurfaceIds) {
- mJpegSurfaceIds = jpegSurfaceIds;
- }
-
- /**
- * Return and remove the next burst on the queue.
- *
- * <p>If a repeating burst is returned, it will not be removed.</p>
- *
- * @return an entry containing the next burst, the current frame number, and flag about whether
- * request queue becomes empty. Null if no burst exists.
- */
- public synchronized RequestQueueEntry getNext() {
- BurstHolder next = mRequestQueue.poll();
- boolean queueEmptied = (next != null && mRequestQueue.size() == 0);
- if (next == null && mRepeatingRequest != null) {
- next = mRepeatingRequest;
- mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
- next.getNumberOfRequests();
- }
-
- if (next == null) {
- return null;
- }
-
- RequestQueueEntry ret = new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied);
- mCurrentFrameNumber += next.getNumberOfRequests();
- return ret;
- }
-
- /**
- * Cancel a repeating request.
- *
- * @param requestId the id of the repeating request to cancel.
- * @return the last frame to be returned from the HAL for the given repeating request, or
- * {@code INVALID_FRAME} if none exists.
- */
- public synchronized long stopRepeating(int requestId) {
- long ret = INVALID_FRAME;
- if (mRepeatingRequest != null && mRepeatingRequest.getRequestId() == requestId) {
- mRepeatingRequest = null;
- ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
- mCurrentRepeatingFrameNumber - 1;
- mCurrentRepeatingFrameNumber = INVALID_FRAME;
- Log.i(TAG, "Repeating capture request cancelled.");
- } else {
- Log.e(TAG, "cancel failed: no repeating request exists for request id: " + requestId);
- }
- return ret;
- }
-
- /**
- * Cancel a repeating request.
- *
- * @return the last frame to be returned from the HAL for the given repeating request, or
- * {@code INVALID_FRAME} if none exists.
- */
- public synchronized long stopRepeating() {
- if (mRepeatingRequest == null) {
- Log.e(TAG, "cancel failed: no repeating request exists.");
- return INVALID_FRAME;
- }
- return stopRepeating(mRepeatingRequest.getRequestId());
- }
-
- /**
- * Add a the given burst to the queue.
- *
- * <p>If the burst is repeating, replace the current repeating burst.</p>
- *
- * @param requests the burst of requests to add to the queue.
- * @param repeating true if the burst is repeating.
- * @return the submission info, including the new request id, and the last frame number, which
- * contains either the frame number of the last frame that will be returned for this request,
- * or the frame number of the last frame that will be returned for the current repeating
- * request if this burst is set to be repeating.
- */
- public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
- int requestId = mCurrentRequestId++;
- BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
- long lastFrame = INVALID_FRAME;
- if (burst.isRepeating()) {
- Log.i(TAG, "Repeating capture request set.");
- if (mRepeatingRequest != null) {
- lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
- mCurrentRepeatingFrameNumber - 1;
- }
- mCurrentRepeatingFrameNumber = INVALID_FRAME;
- mRepeatingRequest = burst;
- } else {
- mRequestQueue.offer(burst);
- lastFrame = calculateLastFrame(burst.getRequestId());
- }
- SubmitInfo info = new SubmitInfo(requestId, lastFrame);
- return info;
- }
-
- private long calculateLastFrame(int requestId) {
- long total = mCurrentFrameNumber;
- for (BurstHolder b : mRequestQueue) {
- total += b.getNumberOfRequests();
- if (b.getRequestId() == requestId) {
- return total - 1;
- }
- }
- throw new IllegalStateException(
- "At least one request must be in the queue to calculate frame number");
- }
-
-}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
deleted file mode 100644
index f9a5029bffaa..000000000000
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.legacy;
-
-import android.graphics.SurfaceTexture;
-import android.hardware.Camera;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.utils.SubmitInfo;
-import android.hardware.camera2.utils.SizeAreaComparator;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.MutableLong;
-import android.util.Pair;
-import android.util.Size;
-import android.view.Surface;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * This class executes requests to the {@link Camera}.
- *
- * <p>
- * The main components of this class are:
- * - A message queue of requests to the {@link Camera}.
- * - A thread that consumes requests to the {@link Camera} and executes them.
- * - A {@link GLThreadManager} that draws to the configured output {@link Surface}s.
- * - An {@link CameraDeviceState} state machine that manages the callbacks for various operations.
- * </p>
- */
-@SuppressWarnings("deprecation")
-public class RequestThreadManager {
- private final String TAG;
- private final int mCameraId;
- private final RequestHandlerThread mRequestThread;
-
- private static final boolean DEBUG = false;
- // For slightly more spammy messages that will get repeated every frame
- private static final boolean VERBOSE = false;
- private Camera mCamera;
- private final CameraCharacteristics mCharacteristics;
-
- private final CameraDeviceState mDeviceState;
- private final CaptureCollector mCaptureCollector;
- private final LegacyFocusStateMapper mFocusStateMapper;
- private final LegacyFaceDetectMapper mFaceDetectMapper;
-
- private static final int MSG_CONFIGURE_OUTPUTS = 1;
- private static final int MSG_SUBMIT_CAPTURE_REQUEST = 2;
- private static final int MSG_CLEANUP = 3;
-
- private static final int MAX_IN_FLIGHT_REQUESTS = 2;
-
- private static final int PREVIEW_FRAME_TIMEOUT = 1000; // ms
- private static final int JPEG_FRAME_TIMEOUT = 4000; // ms (same as CTS for API2)
- private static final int REQUEST_COMPLETE_TIMEOUT = JPEG_FRAME_TIMEOUT;
-
- private static final float ASPECT_RATIO_TOLERANCE = 0.01f;
- private boolean mPreviewRunning = false;
-
- private final List<Surface> mPreviewOutputs = new ArrayList<>();
- private final List<Surface> mCallbackOutputs = new ArrayList<>();
- private GLThreadManager mGLThreadManager;
- private SurfaceTexture mPreviewTexture;
- private Camera.Parameters mParams;
-
- private final List<Long> mJpegSurfaceIds = new ArrayList<>();
-
- private Size mIntermediateBufferSize;
-
- private final RequestQueue mRequestQueue = new RequestQueue(mJpegSurfaceIds);
- private LegacyRequest mLastRequest = null;
- private SurfaceTexture mDummyTexture;
- private Surface mDummySurface;
-
- private final Object mIdleLock = new Object();
- private final FpsCounter mPrevCounter = new FpsCounter("Incoming Preview");
- private final FpsCounter mRequestCounter = new FpsCounter("Incoming Requests");
-
- private final AtomicBoolean mQuit = new AtomicBoolean(false);
-
- // Stuff JPEGs into HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers to get around SW write
- // limitations for (b/17379185).
- private static final boolean USE_BLOB_FORMAT_OVERRIDE = true;
-
- /**
- * Container object for Configure messages.
- */
- private static class ConfigureHolder {
- public final ConditionVariable condition;
- public final Collection<Pair<Surface, Size>> surfaces;
-
- public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface,
- Size>> surfaces) {
- this.condition = condition;
- this.surfaces = surfaces;
- }
- }
-
- /**
- * Counter class used to calculate and log the current FPS of frame production.
- */
- public static class FpsCounter {
- //TODO: Hook this up to SystTrace?
- private static final String TAG = "FpsCounter";
- private int mFrameCount = 0;
- private long mLastTime = 0;
- private long mLastPrintTime = 0;
- private double mLastFps = 0;
- private final String mStreamType;
- private static final long NANO_PER_SECOND = 1000000000; //ns
-
- public FpsCounter(String streamType) {
- mStreamType = streamType;
- }
-
- public synchronized void countFrame() {
- mFrameCount++;
- long nextTime = SystemClock.elapsedRealtimeNanos();
- if (mLastTime == 0) {
- mLastTime = nextTime;
- }
- if (nextTime > mLastTime + NANO_PER_SECOND) {
- long elapsed = nextTime - mLastTime;
- mLastFps = mFrameCount * (NANO_PER_SECOND / (double) elapsed);
- mFrameCount = 0;
- mLastTime = nextTime;
- }
- }
-
- public synchronized double checkFps() {
- return mLastFps;
- }
-
- public synchronized void staggeredLog() {
- if (mLastTime > mLastPrintTime + 5 * NANO_PER_SECOND) {
- mLastPrintTime = mLastTime;
- Log.d(TAG, "FPS for " + mStreamType + " stream: " + mLastFps );
- }
- }
-
- public synchronized void countAndLog() {
- countFrame();
- staggeredLog();
- }
- }
- /**
- * Fake preview for jpeg captures when there is no active preview
- */
- private void createDummySurface() {
- if (mDummyTexture == null || mDummySurface == null) {
- mDummyTexture = new SurfaceTexture(/*ignored*/0);
- // TODO: use smallest default sizes
- mDummyTexture.setDefaultBufferSize(640, 480);
- mDummySurface = new Surface(mDummyTexture);
- }
- }
-
- private final Camera.ErrorCallback mErrorCallback = new Camera.ErrorCallback() {
- @Override
- public void onError(int i, Camera camera) {
- switch(i) {
- case Camera.CAMERA_ERROR_EVICTED: {
- flush();
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED);
- } break;
- case Camera.CAMERA_ERROR_DISABLED: {
- flush();
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISABLED);
- } break;
- default: {
- Log.e(TAG, "Received error " + i + " from the Camera1 ErrorCallback");
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- } break;
- }
- }
- };
-
- private final ConditionVariable mReceivedJpeg = new ConditionVariable(false);
-
- private final Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
- @Override
- public void onPictureTaken(byte[] data, Camera camera) {
- Log.i(TAG, "Received jpeg.");
- Pair<RequestHolder, Long> captureInfo = mCaptureCollector.jpegProduced();
- if (captureInfo == null || captureInfo.first == null) {
- Log.e(TAG, "Dropping jpeg frame.");
- return;
- }
- RequestHolder holder = captureInfo.first;
- long timestamp = captureInfo.second;
- for (Surface s : holder.getHolderTargets()) {
- try {
- if (LegacyCameraDevice.containsSurfaceId(s, mJpegSurfaceIds)) {
- Log.i(TAG, "Producing jpeg buffer...");
-
- int totalSize = data.length + LegacyCameraDevice.nativeGetJpegFooterSize();
- totalSize = (totalSize + 3) & ~0x3; // round up to nearest octonibble
- LegacyCameraDevice.setNextTimestamp(s, timestamp);
-
- if (USE_BLOB_FORMAT_OVERRIDE) {
- // Override to RGBA_8888 format.
- LegacyCameraDevice.setSurfaceFormat(s,
- LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888);
-
- int dimen = (int) Math.ceil(Math.sqrt(totalSize));
- dimen = (dimen + 0xf) & ~0xf; // round up to nearest multiple of 16
- LegacyCameraDevice.setSurfaceDimens(s, dimen, dimen);
- LegacyCameraDevice.produceFrame(s, data, dimen, dimen,
- CameraMetadataNative.NATIVE_JPEG_FORMAT);
- } else {
- LegacyCameraDevice.setSurfaceDimens(s, totalSize, /*height*/1);
- LegacyCameraDevice.produceFrame(s, data, totalSize, /*height*/1,
- CameraMetadataNative.NATIVE_JPEG_FORMAT);
- }
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, dropping frame. ", e);
- }
- }
-
- mReceivedJpeg.open();
- }
- };
-
- private final Camera.ShutterCallback mJpegShutterCallback = new Camera.ShutterCallback() {
- @Override
- public void onShutter() {
- mCaptureCollector.jpegCaptured(SystemClock.elapsedRealtimeNanos());
- }
- };
-
- private final SurfaceTexture.OnFrameAvailableListener mPreviewCallback =
- new SurfaceTexture.OnFrameAvailableListener() {
- @Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- if (DEBUG) {
- mPrevCounter.countAndLog();
- }
- mGLThreadManager.queueNewFrame();
- }
- };
-
- private void stopPreview() {
- if (VERBOSE) {
- Log.v(TAG, "stopPreview - preview running? " + mPreviewRunning);
- }
- if (mPreviewRunning) {
- mCamera.stopPreview();
- mPreviewRunning = false;
- }
- }
-
- private void startPreview() {
- if (VERBOSE) {
- Log.v(TAG, "startPreview - preview running? " + mPreviewRunning);
- }
- if (!mPreviewRunning) {
- // XX: CameraClient:;startPreview is not getting called after a stop
- mCamera.startPreview();
- mPreviewRunning = true;
- }
- }
-
- private void doJpegCapturePrepare(RequestHolder request) throws IOException {
- if (DEBUG) Log.d(TAG, "doJpegCapturePrepare - preview running? " + mPreviewRunning);
-
- if (!mPreviewRunning) {
- if (DEBUG) Log.d(TAG, "doJpegCapture - create fake surface");
-
- createDummySurface();
- mCamera.setPreviewTexture(mDummyTexture);
- startPreview();
- }
- }
-
- private void doJpegCapture(RequestHolder request) {
- if (DEBUG) Log.d(TAG, "doJpegCapturePrepare");
-
- mCamera.takePicture(mJpegShutterCallback, /*raw*/null, mJpegCallback);
- mPreviewRunning = false;
- }
-
- private void doPreviewCapture(RequestHolder request) throws IOException {
- if (VERBOSE) {
- Log.v(TAG, "doPreviewCapture - preview running? " + mPreviewRunning);
- }
-
- if (mPreviewRunning) {
- return; // Already running
- }
-
- if (mPreviewTexture == null) {
- throw new IllegalStateException(
- "Preview capture called with no preview surfaces configured.");
- }
-
- mPreviewTexture.setDefaultBufferSize(mIntermediateBufferSize.getWidth(),
- mIntermediateBufferSize.getHeight());
- mCamera.setPreviewTexture(mPreviewTexture);
-
- startPreview();
- }
-
- private void disconnectCallbackSurfaces() {
- for (Surface s : mCallbackOutputs) {
- try {
- LegacyCameraDevice.disconnectSurface(s);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.d(TAG, "Surface abandoned, skipping...", e);
- }
- }
- }
-
- private void configureOutputs(Collection<Pair<Surface, Size>> outputs) {
- if (DEBUG) {
- String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces");
- Log.d(TAG, "configureOutputs with " + outputsStr);
- }
-
- try {
- stopPreview();
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception in configure call: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- return;
- }
-
- /*
- * Try to release the previous preview's surface texture earlier if we end up
- * using a different one; this also reduces the likelihood of getting into a deadlock
- * when disconnecting from the old previous texture at a later time.
- */
- try {
- mCamera.setPreviewTexture(/*surfaceTexture*/null);
- } catch (IOException e) {
- Log.w(TAG, "Failed to clear prior SurfaceTexture, may cause GL deadlock: ", e);
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception in configure call: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- return;
- }
-
- if (mGLThreadManager != null) {
- mGLThreadManager.waitUntilStarted();
- mGLThreadManager.ignoreNewFrames();
- mGLThreadManager.waitUntilIdle();
- }
- resetJpegSurfaceFormats(mCallbackOutputs);
- disconnectCallbackSurfaces();
-
- mPreviewOutputs.clear();
- mCallbackOutputs.clear();
- mJpegSurfaceIds.clear();
- mPreviewTexture = null;
-
- List<Size> previewOutputSizes = new ArrayList<>();
- List<Size> callbackOutputSizes = new ArrayList<>();
-
- int facing = mCharacteristics.get(CameraCharacteristics.LENS_FACING);
- int orientation = mCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
- if (outputs != null) {
- for (Pair<Surface, Size> outPair : outputs) {
- Surface s = outPair.first;
- Size outSize = outPair.second;
- try {
- int format = LegacyCameraDevice.detectSurfaceType(s);
- LegacyCameraDevice.setSurfaceOrientation(s, facing, orientation);
- switch (format) {
- case CameraMetadataNative.NATIVE_JPEG_FORMAT:
- if (USE_BLOB_FORMAT_OVERRIDE) {
- // Override to RGBA_8888 format.
- LegacyCameraDevice.setSurfaceFormat(s,
- LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888);
- }
- mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
- mCallbackOutputs.add(s);
- callbackOutputSizes.add(outSize);
-
- // LegacyCameraDevice is the producer of JPEG output surfaces
- // so LegacyCameraDevice needs to connect to the surfaces.
- LegacyCameraDevice.connectSurface(s);
- break;
- default:
- LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- mPreviewOutputs.add(s);
- previewOutputSizes.add(outSize);
- break;
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- }
- try {
- mParams = mCamera.getParameters();
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- return;
- }
-
- List<int[]> supportedFpsRanges = mParams.getSupportedPreviewFpsRange();
- int[] bestRange = getPhotoPreviewFpsRange(supportedFpsRanges);
- if (DEBUG) {
- Log.d(TAG, "doPreviewCapture - Selected range [" +
- bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] + "," +
- bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] + "]");
- }
- mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
-
- Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
- callbackOutputSizes, mParams);
-
- if (previewOutputSizes.size() > 0) {
-
- Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes);
-
- // Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
- Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams);
-
- Size chosenJpegDimen = (smallestSupportedJpegSize != null) ? smallestSupportedJpegSize
- : largestJpegDimen;
-
- List<Size> supportedPreviewSizes = ParameterUtils.convertSizeList(
- mParams.getSupportedPreviewSizes());
-
- // Use smallest preview dimension with same aspect ratio as sensor that is >= than all
- // of the configured output dimensions. If none exists, fall back to using the largest
- // supported preview size.
- long largestOutputArea = largestOutput.getHeight() * (long) largestOutput.getWidth();
- Size bestPreviewDimen = SizeAreaComparator.findLargestByArea(supportedPreviewSizes);
- for (Size s : supportedPreviewSizes) {
- long currArea = s.getWidth() * s.getHeight();
- long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight();
- if (checkAspectRatiosMatch(chosenJpegDimen, s) && (currArea < bestArea &&
- currArea >= largestOutputArea)) {
- bestPreviewDimen = s;
- }
- }
-
- mIntermediateBufferSize = bestPreviewDimen;
- mParams.setPreviewSize(mIntermediateBufferSize.getWidth(),
- mIntermediateBufferSize.getHeight());
-
- if (DEBUG) {
- Log.d(TAG, "Intermediate buffer selected with dimens: " +
- bestPreviewDimen.toString());
- }
- } else {
- mIntermediateBufferSize = null;
- if (DEBUG) {
- Log.d(TAG, "No Intermediate buffer selected, no preview outputs were configured");
- }
- }
-
- if (smallestSupportedJpegSize != null) {
- /*
- * Set takePicture size to the smallest supported JPEG size large enough
- * to scale/crop out of for the bounding rectangle of the configured JPEG sizes.
- */
-
- Log.i(TAG, "configureOutputs - set take picture size to " + smallestSupportedJpegSize);
- mParams.setPictureSize(
- smallestSupportedJpegSize.getWidth(), smallestSupportedJpegSize.getHeight());
- }
-
- // TODO: Detect and optimize single-output paths here to skip stream teeing.
- if (mGLThreadManager == null) {
- mGLThreadManager = new GLThreadManager(mCameraId, facing, mDeviceState);
- mGLThreadManager.start();
- }
- mGLThreadManager.waitUntilStarted();
- List<Pair<Surface, Size>> previews = new ArrayList<>();
- Iterator<Size> previewSizeIter = previewOutputSizes.iterator();
- for (Surface p : mPreviewOutputs) {
- previews.add(new Pair<>(p, previewSizeIter.next()));
- }
- mGLThreadManager.setConfigurationAndWait(previews, mCaptureCollector);
-
- for (Surface p : mPreviewOutputs) {
- try {
- LegacyCameraDevice.setSurfaceOrientation(p, facing, orientation);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.e(TAG, "Surface abandoned, skipping setSurfaceOrientation()", e);
- }
- }
-
- mGLThreadManager.allowNewFrames();
- mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
- if (mPreviewTexture != null) {
- mPreviewTexture.setOnFrameAvailableListener(mPreviewCallback);
- }
-
- try {
- mCamera.setParameters(mParams);
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception while configuring: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
-
- }
- }
-
- private void resetJpegSurfaceFormats(Collection<Surface> surfaces) {
- if (!USE_BLOB_FORMAT_OVERRIDE || surfaces == null) {
- return;
- }
- for(Surface s : surfaces) {
- if (s == null || !s.isValid()) {
- Log.w(TAG, "Jpeg surface is invalid, skipping...");
- continue;
- }
- try {
- LegacyCameraDevice.setSurfaceFormat(s, LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- }
-
- /**
- * Find a JPEG size (that is supported by the legacy camera device) which is equal to or larger
- * than all of the configured {@code JPEG} outputs (by both width and height).
- *
- * <p>If multiple supported JPEG sizes are larger, select the smallest of them which
- * still satisfies the above constraint.</p>
- *
- * <p>As a result, the returned size is guaranteed to be usable without needing
- * to upscale any of the outputs. If only one {@code JPEG} surface is used,
- * then no scaling/cropping is necessary between the taken picture and
- * the {@code JPEG} output surface.</p>
- *
- * @param callbackOutputs a non-{@code null} list of {@code Surface}s with any image formats
- * @param params api1 parameters (used for reading only)
- *
- * @return a size large enough to fit all of the configured {@code JPEG} outputs, or
- * {@code null} if the {@code callbackOutputs} did not have any {@code JPEG}
- * surfaces.
- */
- private Size calculatePictureSize( List<Surface> callbackOutputs,
- List<Size> callbackSizes, Camera.Parameters params) {
- /*
- * Find the largest JPEG size (if any), from the configured outputs:
- * - the api1 picture size should be set to the smallest legal size that's at least as large
- * as the largest configured JPEG size
- */
- if (callbackOutputs.size() != callbackSizes.size()) {
- throw new IllegalStateException("Input collections must be same length");
- }
- List<Size> configuredJpegSizes = new ArrayList<>();
- Iterator<Size> sizeIterator = callbackSizes.iterator();
- for (Surface callbackSurface : callbackOutputs) {
- Size jpegSize = sizeIterator.next();
- if (!LegacyCameraDevice.containsSurfaceId(callbackSurface, mJpegSurfaceIds)) {
- continue; // Ignore non-JPEG callback formats
- }
-
- configuredJpegSizes.add(jpegSize);
- }
- if (!configuredJpegSizes.isEmpty()) {
- /*
- * Find the largest configured JPEG width, and height, independently
- * of the rest.
- *
- * The rest of the JPEG streams can be cropped out of this smallest bounding
- * rectangle.
- */
- int maxConfiguredJpegWidth = -1;
- int maxConfiguredJpegHeight = -1;
- for (Size jpegSize : configuredJpegSizes) {
- maxConfiguredJpegWidth = jpegSize.getWidth() > maxConfiguredJpegWidth ?
- jpegSize.getWidth() : maxConfiguredJpegWidth;
- maxConfiguredJpegHeight = jpegSize.getHeight() > maxConfiguredJpegHeight ?
- jpegSize.getHeight() : maxConfiguredJpegHeight;
- }
- Size smallestBoundJpegSize = new Size(maxConfiguredJpegWidth, maxConfiguredJpegHeight);
-
- List<Size> supportedJpegSizes = ParameterUtils.convertSizeList(
- params.getSupportedPictureSizes());
-
- /*
- * Find the smallest supported JPEG size that can fit the smallest bounding
- * rectangle for the configured JPEG sizes.
- */
- List<Size> candidateSupportedJpegSizes = new ArrayList<>();
- for (Size supportedJpegSize : supportedJpegSizes) {
- if (supportedJpegSize.getWidth() >= maxConfiguredJpegWidth &&
- supportedJpegSize.getHeight() >= maxConfiguredJpegHeight) {
- candidateSupportedJpegSizes.add(supportedJpegSize);
- }
- }
-
- if (candidateSupportedJpegSizes.isEmpty()) {
- throw new AssertionError(
- "Could not find any supported JPEG sizes large enough to fit " +
- smallestBoundJpegSize);
- }
-
- Size smallestSupportedJpegSize = Collections.min(candidateSupportedJpegSizes,
- new SizeAreaComparator());
-
- if (!smallestSupportedJpegSize.equals(smallestBoundJpegSize)) {
- Log.w(TAG,
- String.format(
- "configureOutputs - Will need to crop picture %s into "
- + "smallest bound size %s",
- smallestSupportedJpegSize, smallestBoundJpegSize));
- }
-
- return smallestSupportedJpegSize;
- }
-
- return null;
- }
-
- private static boolean checkAspectRatiosMatch(Size a, Size b) {
- float aAspect = a.getWidth() / (float) a.getHeight();
- float bAspect = b.getWidth() / (float) b.getHeight();
-
- return Math.abs(aAspect - bAspect) < ASPECT_RATIO_TOLERANCE;
- }
-
- // Calculate the highest FPS range supported
- private int[] getPhotoPreviewFpsRange(List<int[]> frameRates) {
- if (frameRates.size() == 0) {
- Log.e(TAG, "No supported frame rates returned!");
- return null;
- }
-
- int bestMin = 0;
- int bestMax = 0;
- int bestIndex = 0;
- int index = 0;
- for (int[] rate : frameRates) {
- int minFps = rate[Camera.Parameters.PREVIEW_FPS_MIN_INDEX];
- int maxFps = rate[Camera.Parameters.PREVIEW_FPS_MAX_INDEX];
- if (maxFps > bestMax || (maxFps == bestMax && minFps > bestMin)) {
- bestMin = minFps;
- bestMax = maxFps;
- bestIndex = index;
- }
- index++;
- }
-
- return frameRates.get(bestIndex);
- }
-
- private final Handler.Callback mRequestHandlerCb = new Handler.Callback() {
- private boolean mCleanup = false;
- private final LegacyResultMapper mMapper = new LegacyResultMapper();
-
- @Override
- public boolean handleMessage(Message msg) {
- if (mCleanup) {
- return true;
- }
-
- if (DEBUG) {
- Log.d(TAG, "Request thread handling message:" + msg.what);
- }
- long startTime = 0;
- if (DEBUG) {
- startTime = SystemClock.elapsedRealtimeNanos();
- }
- switch (msg.what) {
- case MSG_CONFIGURE_OUTPUTS:
- ConfigureHolder config = (ConfigureHolder) msg.obj;
- int sizes = config.surfaces != null ? config.surfaces.size() : 0;
- Log.i(TAG, "Configure outputs: " + sizes + " surfaces configured.");
-
- try {
- boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
- TimeUnit.MILLISECONDS);
- if (!success) {
- Log.e(TAG, "Timed out while queueing configure request.");
- mCaptureCollector.failAll();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for requests to complete.");
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- }
-
- configureOutputs(config.surfaces);
- config.condition.open();
- if (DEBUG) {
- long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
- Log.d(TAG, "Configure took " + totalTime + " ns");
- }
- break;
- case MSG_SUBMIT_CAPTURE_REQUEST:
- Handler handler = RequestThreadManager.this.mRequestThread.getHandler();
- boolean anyRequestOutputAbandoned = false;
-
- // Get the next burst from the request queue.
- RequestQueue.RequestQueueEntry nextBurst = mRequestQueue.getNext();
-
- if (nextBurst == null) {
- // If there are no further requests queued, wait for any currently executing
- // requests to complete, then switch to idle state.
- try {
- boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
- TimeUnit.MILLISECONDS);
- if (!success) {
- Log.e(TAG,
- "Timed out while waiting for prior requests to complete.");
- mCaptureCollector.failAll();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for requests to complete: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- }
-
- synchronized (mIdleLock) {
- // Retry the the request queue.
- nextBurst = mRequestQueue.getNext();
-
- // If we still have no queued requests, go idle.
- if (nextBurst == null) {
- mDeviceState.setIdle();
- break;
- }
- }
- }
-
- if (nextBurst != null) {
- // Queue another capture if we did not get the last burst.
- handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
-
- // Check whether capture queue becomes empty
- if (nextBurst.isQueueEmpty()) {
- mDeviceState.setRequestQueueEmpty();
- }
- }
-
- // Complete each request in the burst
- BurstHolder burstHolder = nextBurst.getBurstHolder();
- List<RequestHolder> requests =
- burstHolder.produceRequestHolders(nextBurst.getFrameNumber());
- for (RequestHolder holder : requests) {
- CaptureRequest request = holder.getRequest();
-
- boolean paramsChanged = false;
-
- // Only update parameters if the request has changed
- if (mLastRequest == null || mLastRequest.captureRequest != request) {
-
- // The intermediate buffer is sometimes null, but we always need
- // the Camera1 API configured preview size
- Size previewSize = ParameterUtils.convertSize(mParams.getPreviewSize());
-
- LegacyRequest legacyRequest = new LegacyRequest(mCharacteristics,
- request, previewSize, mParams); // params are copied
-
-
- // Parameters are mutated as a side-effect
- LegacyMetadataMapper.convertRequestMetadata(/*inout*/legacyRequest);
-
- // If the parameters have changed, set them in the Camera1 API.
- if (!mParams.same(legacyRequest.parameters)) {
- try {
- mCamera.setParameters(legacyRequest.parameters);
- } catch (RuntimeException e) {
- // If setting the parameters failed, report a request error to
- // the camera client, and skip any further work for this request
- Log.e(TAG, "Exception while setting camera parameters: ", e);
- holder.failRequest();
- mDeviceState.setCaptureStart(holder, /*timestamp*/0,
- CameraDeviceImpl.CameraDeviceCallbacks.
- ERROR_CAMERA_REQUEST);
- continue;
- }
- paramsChanged = true;
- mParams = legacyRequest.parameters;
- }
-
- mLastRequest = legacyRequest;
- }
-
- try {
- boolean success = mCaptureCollector.queueRequest(holder,
- mLastRequest, JPEG_FRAME_TIMEOUT, TimeUnit.MILLISECONDS);
-
- if (!success) {
- // Report a request error if we timed out while queuing this.
- Log.e(TAG, "Timed out while queueing capture request.");
- holder.failRequest();
- mDeviceState.setCaptureStart(holder, /*timestamp*/0,
- CameraDeviceImpl.CameraDeviceCallbacks.
- ERROR_CAMERA_REQUEST);
- continue;
- }
-
- // Starting the preview needs to happen before enabling
- // face detection or auto focus
- if (holder.hasPreviewTargets()) {
- doPreviewCapture(holder);
- }
- if (holder.hasJpegTargets()) {
- while(!mCaptureCollector.waitForPreviewsEmpty(PREVIEW_FRAME_TIMEOUT,
- TimeUnit.MILLISECONDS)) {
- // Fail preview requests until the queue is empty.
- Log.e(TAG, "Timed out while waiting for preview requests to " +
- "complete.");
- mCaptureCollector.failNextPreview();
- }
- mReceivedJpeg.close();
- doJpegCapturePrepare(holder);
- }
-
- /*
- * Do all the actions that require a preview to have been started
- */
-
- // Toggle face detection on/off
- // - do this before AF to give AF a chance to use faces
- mFaceDetectMapper.processFaceDetectMode(request, /*in*/mParams);
-
- // Unconditionally process AF triggers, since they're non-idempotent
- // - must be done after setting the most-up-to-date AF mode
- mFocusStateMapper.processRequestTriggers(request, mParams);
-
- if (holder.hasJpegTargets()) {
- doJpegCapture(holder);
- if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) {
- Log.e(TAG, "Hit timeout for jpeg callback!");
- mCaptureCollector.failNextJpeg();
- }
- }
-
- } catch (IOException e) {
- Log.e(TAG, "Received device exception during capture call: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted during capture: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception during capture call: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- }
-
- if (paramsChanged) {
- if (DEBUG) {
- Log.d(TAG, "Params changed -- getting new Parameters from HAL.");
- }
- try {
- mParams = mCamera.getParameters();
- } catch (RuntimeException e) {
- Log.e(TAG, "Received device exception: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- }
-
- // Update parameters to the latest that we think the camera is using
- mLastRequest.setParameters(mParams);
- }
-
- MutableLong timestampMutable = new MutableLong(/*value*/0L);
- try {
- boolean success = mCaptureCollector.waitForRequestCompleted(holder,
- REQUEST_COMPLETE_TIMEOUT, TimeUnit.MILLISECONDS,
- /*out*/timestampMutable);
-
- if (!success) {
- Log.e(TAG, "Timed out while waiting for request to complete.");
- mCaptureCollector.failAll();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted waiting for request completion: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- break;
- }
-
- CameraMetadataNative result = mMapper.cachedConvertResultMetadata(
- mLastRequest, timestampMutable.value);
- /*
- * Order matters: The default result mapper is state-less; the
- * other mappers carry state and may override keys set by the default
- * mapper with their own values.
- */
-
- // Update AF state
- mFocusStateMapper.mapResultTriggers(result);
- // Update face-related results
- mFaceDetectMapper.mapResultFaces(result, mLastRequest);
-
- if (!holder.requestFailed()) {
- mDeviceState.setCaptureResult(holder, result);
- }
-
- if (holder.isOutputAbandoned()) {
- anyRequestOutputAbandoned = true;
- }
- }
-
- // Stop the repeating request if any of its output surfaces is abandoned.
- if (anyRequestOutputAbandoned && burstHolder.isRepeating()) {
- long lastFrameNumber = cancelRepeating(burstHolder.getRequestId());
- if (DEBUG) {
- Log.d(TAG, "Stopped repeating request. Last frame number is " +
- lastFrameNumber);
- }
- if (lastFrameNumber != RequestQueue.INVALID_FRAME) {
- mDeviceState.setRepeatingRequestError(lastFrameNumber,
- burstHolder.getRequestId());
- } else {
- Log.e(TAG, "Repeating request id: " + burstHolder.getRequestId() +
- " already canceled!");
- }
- }
-
- if (DEBUG) {
- long totalTime = SystemClock.elapsedRealtimeNanos() - startTime;
- Log.d(TAG, "Capture request took " + totalTime + " ns");
- mRequestCounter.countAndLog();
- }
- break;
- case MSG_CLEANUP:
- mCleanup = true;
- try {
- boolean success = mCaptureCollector.waitForEmpty(JPEG_FRAME_TIMEOUT,
- TimeUnit.MILLISECONDS);
- if (!success) {
- Log.e(TAG, "Timed out while queueing cleanup request.");
- mCaptureCollector.failAll();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while waiting for requests to complete: ", e);
- mDeviceState.setError(
- CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
- }
- if (mGLThreadManager != null) {
- mGLThreadManager.quit();
- mGLThreadManager = null;
- }
- disconnectCallbackSurfaces();
- if (mCamera != null) {
- mCamera.release();
- mCamera = null;
- }
- break;
- case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
- // OK: Ignore message.
- break;
- default:
- throw new AssertionError("Unhandled message " + msg.what +
- " on RequestThread.");
- }
- return true;
- }
- };
-
- /**
- * Create a new RequestThreadManager.
- *
- * @param cameraId the id of the camera to use.
- * @param camera an open camera object. The RequestThreadManager takes ownership of this camera
- * object, and is responsible for closing it.
- * @param characteristics the static camera characteristics corresponding to this camera device
- * @param deviceState a {@link CameraDeviceState} state machine.
- */
- public RequestThreadManager(int cameraId, Camera camera, CameraCharacteristics characteristics,
- CameraDeviceState deviceState) {
- mCamera = checkNotNull(camera, "camera must not be null");
- mCameraId = cameraId;
- mCharacteristics = checkNotNull(characteristics, "characteristics must not be null");
- String name = String.format("RequestThread-%d", cameraId);
- TAG = name;
- mDeviceState = checkNotNull(deviceState, "deviceState must not be null");
- mFocusStateMapper = new LegacyFocusStateMapper(mCamera);
- mFaceDetectMapper = new LegacyFaceDetectMapper(mCamera, mCharacteristics);
- mCaptureCollector = new CaptureCollector(MAX_IN_FLIGHT_REQUESTS, mDeviceState);
- mRequestThread = new RequestHandlerThread(name, mRequestHandlerCb);
- mCamera.setDetailedErrorCallback(mErrorCallback);
- }
-
- /**
- * Start the request thread.
- */
- public void start() {
- mRequestThread.start();
- }
-
- /**
- * Flush any pending requests.
- *
- * @return the last frame number.
- */
- public long flush() {
- Log.i(TAG, "Flushing all pending requests.");
- long lastFrame = mRequestQueue.stopRepeating();
- mCaptureCollector.failAll();
- return lastFrame;
- }
-
- /**
- * Quit the request thread, and clean up everything.
- */
- public void quit() {
- if (!mQuit.getAndSet(true)) { // Avoid sending messages on dead thread's handler.
- Handler handler = mRequestThread.waitAndGetHandler();
- handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
- mRequestThread.quitSafely();
- try {
- mRequestThread.join();
- } catch (InterruptedException e) {
- Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
- mRequestThread.getName(), mRequestThread.getId()));
- }
- }
- }
-
- /**
- * Submit the given burst of requests to be captured.
- *
- * <p>If the burst is repeating, replace the current repeating burst.</p>
- *
- * @param requests the burst of requests to add to the queue.
- * @param repeating true if the burst is repeating.
- * @return the submission info, including the new request id, and the last frame number, which
- * contains either the frame number of the last frame that will be returned for this request,
- * or the frame number of the last frame that will be returned for the current repeating
- * request if this burst is set to be repeating.
- */
- public SubmitInfo submitCaptureRequests(CaptureRequest[] requests, boolean repeating) {
- Handler handler = mRequestThread.waitAndGetHandler();
- SubmitInfo info;
- synchronized (mIdleLock) {
- info = mRequestQueue.submit(requests, repeating);
- handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
- }
- return info;
- }
-
- /**
- * Cancel a repeating request.
- *
- * @param requestId the id of the repeating request to cancel.
- * @return the last frame to be returned from the HAL for the given repeating request, or
- * {@code INVALID_FRAME} if none exists.
- */
- public long cancelRepeating(int requestId) {
- return mRequestQueue.stopRepeating(requestId);
- }
-
- /**
- * Configure with the current list of output Surfaces.
- *
- * <p>
- * This operation blocks until the configuration is complete.
- * </p>
- *
- * <p>Using a {@code null} or empty {@code outputs} list is the equivalent of unconfiguring.</p>
- *
- * @param outputs a {@link java.util.Collection} of outputs to configure.
- */
- public void configure(Collection<Pair<Surface, Size>> outputs) {
- Handler handler = mRequestThread.waitAndGetHandler();
- final ConditionVariable condition = new ConditionVariable(/*closed*/false);
- ConfigureHolder holder = new ConfigureHolder(condition, outputs);
- handler.sendMessage(handler.obtainMessage(MSG_CONFIGURE_OUTPUTS, 0, 0, holder));
- condition.block();
- }
-
- public void setAudioRestriction(int mode) {
- if (mCamera != null) {
- mCamera.setAudioRestriction(mode);
- }
- throw new IllegalStateException("Camera has been released!");
- }
-
- public int getAudioRestriction() {
- if (mCamera != null) {
- return mCamera.getAudioRestriction();
- }
- throw new IllegalStateException("Camera has been released!");
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/SizeAreaComparator.java b/core/java/android/hardware/camera2/legacy/SizeAreaComparator.java
deleted file mode 100644
index 75a5bab94867..000000000000
--- a/core/java/android/hardware/camera2/legacy/SizeAreaComparator.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.hardware.camera2.legacy;
-
-import android.hardware.Camera;
-
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import static com.android.internal.util.Preconditions.*;
-
-/**
- * Comparator for api1 {@link Camera.Size} objects by the area.
- *
- * <p>This comparator totally orders by rectangle area. Tie-breaks on width.</p>
- */
-@SuppressWarnings("deprecation")
-public class SizeAreaComparator implements Comparator<Camera.Size> {
- /**
- * {@inheritDoc}
- */
- @Override
- public int compare(Camera.Size size, Camera.Size size2) {
- checkNotNull(size, "size must not be null");
- checkNotNull(size2, "size2 must not be null");
-
- if (size.equals(size2)) {
- return 0;
- }
-
- long width = size.width;
- long width2 = size2.width;
- long area = width * size.height;
- long area2 = width2 * size2.height;
-
- if (area == area2) {
- return (width > width2) ? 1 : -1;
- }
-
- return (area > area2) ? 1 : -1;
- }
-
- /**
- * Get the largest api1 {@code Camera.Size} from the list by comparing each size's area
- * by each other using {@link SizeAreaComparator}.
- *
- * @param sizes a non-{@code null} list of non-{@code null} sizes
- * @return a non-{@code null} size
- *
- * @throws NullPointerException if {@code sizes} or any elements in it were {@code null}
- */
- public static Camera.Size findLargestByArea(List<Camera.Size> sizes) {
- checkNotNull(sizes, "sizes must not be null");
-
- return Collections.max(sizes, new SizeAreaComparator());
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
deleted file mode 100644
index a4c65aeb1050..000000000000
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.camera2.legacy;
-
-import android.graphics.ImageFormat;
-import android.graphics.RectF;
-import android.graphics.SurfaceTexture;
-import android.hardware.camera2.CameraCharacteristics;
-import android.os.Environment;
-import android.opengl.EGL14;
-import android.opengl.EGLConfig;
-import android.opengl.EGLContext;
-import android.opengl.EGLDisplay;
-import android.opengl.EGLSurface;
-import android.opengl.GLES11Ext;
-import android.opengl.GLES20;
-import android.opengl.Matrix;
-import android.util.Log;
-import android.util.Pair;
-import android.util.Size;
-import android.view.Surface;
-import android.os.SystemProperties;
-
-import java.io.File;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * A renderer class that manages the GL state, and can draw a frame into a set of output
- * {@link Surface}s.
- */
-public class SurfaceTextureRenderer {
- private static final String TAG = SurfaceTextureRenderer.class.getSimpleName();
- private static final boolean DEBUG = false;
- private static final int EGL_RECORDABLE_ANDROID = 0x3142; // from EGL/eglext.h
- private static final int GL_MATRIX_SIZE = 16;
- private static final int VERTEX_POS_SIZE = 3;
- private static final int VERTEX_UV_SIZE = 2;
- private static final int EGL_COLOR_BITLENGTH = 8;
- private static final int GLES_VERSION = 2;
- private static final int PBUFFER_PIXEL_BYTES = 4;
-
- private static final int FLIP_TYPE_NONE = 0;
- private static final int FLIP_TYPE_HORIZONTAL = 1;
- private static final int FLIP_TYPE_VERTICAL = 2;
- private static final int FLIP_TYPE_BOTH = FLIP_TYPE_HORIZONTAL | FLIP_TYPE_VERTICAL;
-
- private static final DateTimeFormatter LOG_NAME_TIME_FORMATTER =
- DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss", Locale.ROOT);
-
- private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
- private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
- private EGLConfig mConfigs;
-
- private class EGLSurfaceHolder {
- Surface surface;
- EGLSurface eglSurface;
- int width;
- int height;
- }
-
- private List<EGLSurfaceHolder> mSurfaces = new ArrayList<EGLSurfaceHolder>();
- private List<EGLSurfaceHolder> mConversionSurfaces = new ArrayList<EGLSurfaceHolder>();
-
- private ByteBuffer mPBufferPixels;
-
- // Hold this to avoid GC
- private volatile SurfaceTexture mSurfaceTexture;
-
- private static final int FLOAT_SIZE_BYTES = 4;
- private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
- private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
- private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
-
- // Sampling is mirrored across the horizontal axis
- private static final float[] sHorizontalFlipTriangleVertices = {
- // X, Y, Z, U, V
- -1.0f, -1.0f, 0, 1.f, 0.f,
- 1.0f, -1.0f, 0, 0.f, 0.f,
- -1.0f, 1.0f, 0, 1.f, 1.f,
- 1.0f, 1.0f, 0, 0.f, 1.f,
- };
-
- // Sampling is mirrored across the vertical axis
- private static final float[] sVerticalFlipTriangleVertices = {
- // X, Y, Z, U, V
- -1.0f, -1.0f, 0, 0.f, 1.f,
- 1.0f, -1.0f, 0, 1.f, 1.f,
- -1.0f, 1.0f, 0, 0.f, 0.f,
- 1.0f, 1.0f, 0, 1.f, 0.f,
- };
-
- // Sampling is mirrored across the both axes
- private static final float[] sBothFlipTriangleVertices = {
- // X, Y, Z, U, V
- -1.0f, -1.0f, 0, 1.f, 1.f,
- 1.0f, -1.0f, 0, 0.f, 1.f,
- -1.0f, 1.0f, 0, 1.f, 0.f,
- 1.0f, 1.0f, 0, 0.f, 0.f,
- };
-
- // Sampling is 1:1 for a straight copy for the back camera
- private static final float[] sRegularTriangleVertices = {
- // X, Y, Z, U, V
- -1.0f, -1.0f, 0, 0.f, 0.f,
- 1.0f, -1.0f, 0, 1.f, 0.f,
- -1.0f, 1.0f, 0, 0.f, 1.f,
- 1.0f, 1.0f, 0, 1.f, 1.f,
- };
-
- private FloatBuffer mRegularTriangleVertices;
- private FloatBuffer mHorizontalFlipTriangleVertices;
- private FloatBuffer mVerticalFlipTriangleVertices;
- private FloatBuffer mBothFlipTriangleVertices;
- private final int mFacing;
-
- /**
- * As used in this file, this vertex shader maps a unit square to the view, and
- * tells the fragment shader to interpolate over it. Each surface pixel position
- * is mapped to a 2D homogeneous texture coordinate of the form (s, t, 0, 1) with
- * s and t in the inclusive range [0, 1], and the matrix from
- * {@link SurfaceTexture#getTransformMatrix(float[])} is used to map this
- * coordinate to a texture location.
- */
- private static final String VERTEX_SHADER =
- "uniform mat4 uMVPMatrix;\n" +
- "uniform mat4 uSTMatrix;\n" +
- "attribute vec4 aPosition;\n" +
- "attribute vec4 aTextureCoord;\n" +
- "varying vec2 vTextureCoord;\n" +
- "void main() {\n" +
- " gl_Position = uMVPMatrix * aPosition;\n" +
- " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
- "}\n";
-
- /**
- * This fragment shader simply draws the color in the 2D texture at
- * the location from the {@code VERTEX_SHADER}.
- */
- private static final String FRAGMENT_SHADER =
- "#extension GL_OES_EGL_image_external : require\n" +
- "precision mediump float;\n" +
- "varying vec2 vTextureCoord;\n" +
- "uniform samplerExternalOES sTexture;\n" +
- "void main() {\n" +
- " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
- "}\n";
-
- private float[] mMVPMatrix = new float[GL_MATRIX_SIZE];
- private float[] mSTMatrix = new float[GL_MATRIX_SIZE];
-
- private int mProgram;
- private int mTextureID = 0;
- private int muMVPMatrixHandle;
- private int muSTMatrixHandle;
- private int maPositionHandle;
- private int maTextureHandle;
-
- private PerfMeasurement mPerfMeasurer = null;
- private static final String LEGACY_PERF_PROPERTY = "persist.camera.legacy_perf";
-
- public SurfaceTextureRenderer(int facing) {
- mFacing = facing;
-
- mRegularTriangleVertices = ByteBuffer.allocateDirect(sRegularTriangleVertices.length *
- FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
- mRegularTriangleVertices.put(sRegularTriangleVertices).position(0);
-
- mHorizontalFlipTriangleVertices = ByteBuffer.allocateDirect(
- sHorizontalFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
- order(ByteOrder.nativeOrder()).asFloatBuffer();
- mHorizontalFlipTriangleVertices.put(sHorizontalFlipTriangleVertices).position(0);
-
- mVerticalFlipTriangleVertices = ByteBuffer.allocateDirect(
- sVerticalFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
- order(ByteOrder.nativeOrder()).asFloatBuffer();
- mVerticalFlipTriangleVertices.put(sVerticalFlipTriangleVertices).position(0);
-
- mBothFlipTriangleVertices = ByteBuffer.allocateDirect(
- sBothFlipTriangleVertices.length * FLOAT_SIZE_BYTES).
- order(ByteOrder.nativeOrder()).asFloatBuffer();
- mBothFlipTriangleVertices.put(sBothFlipTriangleVertices).position(0);
-
- Matrix.setIdentityM(mSTMatrix, 0);
- }
-
- private int loadShader(int shaderType, String source) {
- int shader = GLES20.glCreateShader(shaderType);
- checkGlError("glCreateShader type=" + shaderType);
- GLES20.glShaderSource(shader, source);
- GLES20.glCompileShader(shader);
- int[] compiled = new int[1];
- GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
- if (compiled[0] == 0) {
- Log.e(TAG, "Could not compile shader " + shaderType + ":");
- Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
- GLES20.glDeleteShader(shader);
- // TODO: handle this more gracefully
- throw new IllegalStateException("Could not compile shader " + shaderType);
- }
- return shader;
- }
-
- private int createProgram(String vertexSource, String fragmentSource) {
- int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
- if (vertexShader == 0) {
- return 0;
- }
- int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
- if (pixelShader == 0) {
- return 0;
- }
-
- int program = GLES20.glCreateProgram();
- checkGlError("glCreateProgram");
- if (program == 0) {
- Log.e(TAG, "Could not create program");
- }
- GLES20.glAttachShader(program, vertexShader);
- checkGlError("glAttachShader");
- GLES20.glAttachShader(program, pixelShader);
- checkGlError("glAttachShader");
- GLES20.glLinkProgram(program);
- int[] linkStatus = new int[1];
- GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
- if (linkStatus[0] != GLES20.GL_TRUE) {
- Log.e(TAG, "Could not link program: ");
- Log.e(TAG, GLES20.glGetProgramInfoLog(program));
- GLES20.glDeleteProgram(program);
- // TODO: handle this more gracefully
- throw new IllegalStateException("Could not link program");
- }
- return program;
- }
-
- private void drawFrame(SurfaceTexture st, int width, int height, int flipType)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- checkGlError("onDrawFrame start");
- st.getTransformMatrix(mSTMatrix);
-
- Matrix.setIdentityM(mMVPMatrix, /*smOffset*/0);
-
- // Find intermediate buffer dimensions
- Size dimens;
- try {
- dimens = LegacyCameraDevice.getTextureSize(st);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- // Should never hit this.
- throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
- }
- float texWidth = dimens.getWidth();
- float texHeight = dimens.getHeight();
-
- if (texWidth <= 0 || texHeight <= 0) {
- throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
- }
-
- // Letterbox or pillar-box output dimensions into intermediate dimensions.
- RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
- RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
- android.graphics.Matrix boxingXform = new android.graphics.Matrix();
- boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
- boxingXform.mapRect(output);
-
- // Find scaling factor from pillar-boxed/letter-boxed output dimensions to intermediate
- // buffer dimensions.
- float scaleX = intermediate.width() / output.width();
- float scaleY = intermediate.height() / output.height();
-
- // Intermediate texture is implicitly scaled to 'fill' the output dimensions in clip space
- // coordinates in the shader. To avoid stretching, we need to scale the larger dimension
- // of the intermediate buffer so that the output buffer is actually letter-boxed
- // or pillar-boxed into the intermediate buffer after clipping.
- Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleX, /*y*/scaleY, /*z*/1);
-
- if (DEBUG) {
- Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
- width + "x" + height + " surface, intermediate buffer size is " + texWidth +
- "x" + texHeight);
- }
-
- // Set viewport to be output buffer dimensions
- GLES20.glViewport(0, 0, width, height);
-
- if (DEBUG) {
- GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
- GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
- }
-
- GLES20.glUseProgram(mProgram);
- checkGlError("glUseProgram");
-
- GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
-
- FloatBuffer triangleVertices;
- switch(flipType) {
- case FLIP_TYPE_HORIZONTAL:
- triangleVertices = mHorizontalFlipTriangleVertices;
- break;
- case FLIP_TYPE_VERTICAL:
- triangleVertices = mVerticalFlipTriangleVertices;
- break;
- case FLIP_TYPE_BOTH:
- triangleVertices = mBothFlipTriangleVertices;
- break;
- default:
- triangleVertices = mRegularTriangleVertices;
- break;
- }
-
- triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
- GLES20.glVertexAttribPointer(maPositionHandle, VERTEX_POS_SIZE, GLES20.GL_FLOAT,
- /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
- checkGlError("glVertexAttribPointer maPosition");
- GLES20.glEnableVertexAttribArray(maPositionHandle);
- checkGlError("glEnableVertexAttribArray maPositionHandle");
-
- triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
- GLES20.glVertexAttribPointer(maTextureHandle, VERTEX_UV_SIZE, GLES20.GL_FLOAT,
- /*normalized*/ false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
- checkGlError("glVertexAttribPointer maTextureHandle");
- GLES20.glEnableVertexAttribArray(maTextureHandle);
- checkGlError("glEnableVertexAttribArray maTextureHandle");
-
- GLES20.glUniformMatrix4fv(muMVPMatrixHandle, /*count*/ 1, /*transpose*/ false, mMVPMatrix,
- /*offset*/ 0);
- GLES20.glUniformMatrix4fv(muSTMatrixHandle, /*count*/ 1, /*transpose*/ false, mSTMatrix,
- /*offset*/ 0);
-
- GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, /*offset*/ 0, /*count*/ 4);
- checkGlDrawError("glDrawArrays");
- }
-
- /**
- * Initializes GL state. Call this after the EGL surface has been created and made current.
- */
- private void initializeGLState() {
- mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER);
- if (mProgram == 0) {
- throw new IllegalStateException("failed creating program");
- }
- maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
- checkGlError("glGetAttribLocation aPosition");
- if (maPositionHandle == -1) {
- throw new IllegalStateException("Could not get attrib location for aPosition");
- }
- maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
- checkGlError("glGetAttribLocation aTextureCoord");
- if (maTextureHandle == -1) {
- throw new IllegalStateException("Could not get attrib location for aTextureCoord");
- }
-
- muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
- checkGlError("glGetUniformLocation uMVPMatrix");
- if (muMVPMatrixHandle == -1) {
- throw new IllegalStateException("Could not get attrib location for uMVPMatrix");
- }
-
- muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
- checkGlError("glGetUniformLocation uSTMatrix");
- if (muSTMatrixHandle == -1) {
- throw new IllegalStateException("Could not get attrib location for uSTMatrix");
- }
-
- int[] textures = new int[1];
- GLES20.glGenTextures(/*n*/ 1, textures, /*offset*/ 0);
-
- mTextureID = textures[0];
- GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
- checkGlError("glBindTexture mTextureID");
-
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
- GLES20.GL_NEAREST);
- GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
- GLES20.GL_LINEAR);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
- GLES20.GL_CLAMP_TO_EDGE);
- GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
- GLES20.GL_CLAMP_TO_EDGE);
- checkGlError("glTexParameter");
- }
-
- private int getTextureId() {
- return mTextureID;
- }
-
- private void clearState() {
- mSurfaces.clear();
- for (EGLSurfaceHolder holder : mConversionSurfaces) {
- try {
- LegacyCameraDevice.disconnectSurface(holder.surface);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping...", e);
- }
- }
- mConversionSurfaces.clear();
- mPBufferPixels = null;
- if (mSurfaceTexture != null) {
- mSurfaceTexture.release();
- }
- mSurfaceTexture = null;
- }
-
- private void configureEGLContext() {
- mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
- if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
- throw new IllegalStateException("No EGL14 display");
- }
- int[] version = new int[2];
- if (!EGL14.eglInitialize(mEGLDisplay, version, /*offset*/ 0, version, /*offset*/ 1)) {
- throw new IllegalStateException("Cannot initialize EGL14");
- }
-
- int[] attribList = {
- EGL14.EGL_RED_SIZE, EGL_COLOR_BITLENGTH,
- EGL14.EGL_GREEN_SIZE, EGL_COLOR_BITLENGTH,
- EGL14.EGL_BLUE_SIZE, EGL_COLOR_BITLENGTH,
- EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
- EGL_RECORDABLE_ANDROID, 1,
- EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT | EGL14.EGL_WINDOW_BIT,
- EGL14.EGL_NONE
- };
- EGLConfig[] configs = new EGLConfig[1];
- int[] numConfigs = new int[1];
- EGL14.eglChooseConfig(mEGLDisplay, attribList, /*offset*/ 0, configs, /*offset*/ 0,
- configs.length, numConfigs, /*offset*/ 0);
- checkEglError("eglCreateContext RGB888+recordable ES2");
- mConfigs = configs[0];
- int[] attrib_list = {
- EGL14.EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
- EGL14.EGL_NONE
- };
- mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
- attrib_list, /*offset*/ 0);
- checkEglError("eglCreateContext");
- if(mEGLContext == EGL14.EGL_NO_CONTEXT) {
- throw new IllegalStateException("No EGLContext could be made");
- }
- }
-
- private void configureEGLOutputSurfaces(Collection<EGLSurfaceHolder> surfaces) {
- if (surfaces == null || surfaces.size() == 0) {
- throw new IllegalStateException("No Surfaces were provided to draw to");
- }
- int[] surfaceAttribs = {
- EGL14.EGL_NONE
- };
- for (EGLSurfaceHolder holder : surfaces) {
- holder.eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs,
- holder.surface, surfaceAttribs, /*offset*/ 0);
- checkEglError("eglCreateWindowSurface");
- }
- }
-
- private void configureEGLPbufferSurfaces(Collection<EGLSurfaceHolder> surfaces) {
- if (surfaces == null || surfaces.size() == 0) {
- throw new IllegalStateException("No Surfaces were provided to draw to");
- }
-
- int maxLength = 0;
- for (EGLSurfaceHolder holder : surfaces) {
- int length = holder.width * holder.height;
- // Find max surface size, ensure PBuffer can hold this many pixels
- maxLength = (length > maxLength) ? length : maxLength;
- int[] surfaceAttribs = {
- EGL14.EGL_WIDTH, holder.width,
- EGL14.EGL_HEIGHT, holder.height,
- EGL14.EGL_NONE
- };
- holder.eglSurface =
- EGL14.eglCreatePbufferSurface(mEGLDisplay, mConfigs, surfaceAttribs, 0);
- checkEglError("eglCreatePbufferSurface");
- }
- mPBufferPixels = ByteBuffer.allocateDirect(maxLength * PBUFFER_PIXEL_BYTES)
- .order(ByteOrder.nativeOrder());
- }
-
- private void releaseEGLContext() {
- if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
- EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
- EGL14.EGL_NO_CONTEXT);
- dumpGlTiming();
- if (mSurfaces != null) {
- for (EGLSurfaceHolder holder : mSurfaces) {
- if (holder.eglSurface != null) {
- EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
- }
- }
- }
- if (mConversionSurfaces != null) {
- for (EGLSurfaceHolder holder : mConversionSurfaces) {
- if (holder.eglSurface != null) {
- EGL14.eglDestroySurface(mEGLDisplay, holder.eglSurface);
- }
- }
- }
- EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
- EGL14.eglReleaseThread();
- EGL14.eglTerminate(mEGLDisplay);
- }
-
- mConfigs = null;
- mEGLDisplay = EGL14.EGL_NO_DISPLAY;
- mEGLContext = EGL14.EGL_NO_CONTEXT;
- clearState();
- }
-
- private void makeCurrent(EGLSurface surface)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- EGL14.eglMakeCurrent(mEGLDisplay, surface, surface, mEGLContext);
- checkEglDrawError("makeCurrent");
- }
-
- private boolean swapBuffers(EGLSurface surface)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- boolean result = EGL14.eglSwapBuffers(mEGLDisplay, surface);
-
- int error = EGL14.eglGetError();
- switch (error) {
- case EGL14.EGL_SUCCESS:
- return result;
-
- // Check for an abandoned buffer queue, or other error conditions out
- // of the user's control.
- //
- // From the EGL 1.4 spec (2013-12-04), Section 3.9.4 Posting Errors:
- //
- // If eglSwapBuffers is called and the native window associated with
- // surface is no longer valid, an EGL_BAD_NATIVE_WINDOW error is
- // generated.
- //
- // We also interpret EGL_BAD_SURFACE as indicating an abandoned
- // surface, even though the EGL spec does not document it as such, for
- // backwards compatibility with older versions of this file.
- case EGL14.EGL_BAD_NATIVE_WINDOW:
- case EGL14.EGL_BAD_SURFACE:
- throw new LegacyExceptionUtils.BufferQueueAbandonedException();
-
- default:
- throw new IllegalStateException(
- "swapBuffers: EGL error: 0x" + Integer.toHexString(error));
- }
- }
-
- private void checkEglDrawError(String msg)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- int error;
- if ((error = EGL14.eglGetError()) == EGL14.EGL_BAD_NATIVE_WINDOW) {
- throw new LegacyExceptionUtils.BufferQueueAbandonedException();
- }
- if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
- throw new IllegalStateException(msg + ": EGL error: 0x" + Integer.toHexString(error));
- }
- }
-
- private void checkEglError(String msg) {
- int error;
- if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
- throw new IllegalStateException(msg + ": EGL error: 0x" + Integer.toHexString(error));
- }
- }
-
- private void checkGlError(String msg) {
- int error;
- while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
- throw new IllegalStateException(
- msg + ": GLES20 error: 0x" + Integer.toHexString(error));
- }
- }
-
- private void checkGlDrawError(String msg)
- throws LegacyExceptionUtils.BufferQueueAbandonedException {
- int error;
- boolean surfaceAbandoned = false;
- boolean glError = false;
- while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
- if (error == GLES20.GL_OUT_OF_MEMORY) {
- surfaceAbandoned = true;
- } else {
- glError = true;
- }
- }
- if (glError) {
- throw new IllegalStateException(
- msg + ": GLES20 error: 0x" + Integer.toHexString(error));
- }
- if (surfaceAbandoned) {
- throw new LegacyExceptionUtils.BufferQueueAbandonedException();
- }
- }
-
- /**
- * Save a measurement dump to disk, in
- * {@code /sdcard/CameraLegacy/durations_<time>_<width1>x<height1>_...txt}
- */
- private void dumpGlTiming() {
- if (mPerfMeasurer == null) return;
-
- File legacyStorageDir = new File(Environment.getExternalStorageDirectory(), "CameraLegacy");
- if (!legacyStorageDir.exists()){
- if (!legacyStorageDir.mkdirs()){
- Log.e(TAG, "Failed to create directory for data dump");
- return;
- }
- }
-
- StringBuilder path = new StringBuilder(legacyStorageDir.getPath());
- path.append(File.separator);
- path.append("durations_");
-
- path.append(formatTimestamp(System.currentTimeMillis()));
- path.append("_S");
- for (EGLSurfaceHolder surface : mSurfaces) {
- path.append(String.format("_%d_%d", surface.width, surface.height));
- }
- path.append("_C");
- for (EGLSurfaceHolder surface : mConversionSurfaces) {
- path.append(String.format("_%d_%d", surface.width, surface.height));
- }
- path.append(".txt");
- mPerfMeasurer.dumpPerformanceData(path.toString());
- }
-
- private static String formatTimestamp(long timeMillis) {
- // This is a replacement for {@link Time#format2445()} that doesn't suffer from Y2038
- // issues.
- Instant instant = Instant.ofEpochMilli(timeMillis);
- ZoneId zoneId = ZoneId.systemDefault();
- LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
- return LOG_NAME_TIME_FORMATTER.format(localDateTime);
- }
-
- private void setupGlTiming() {
- if (PerfMeasurement.isGlTimingSupported()) {
- Log.d(TAG, "Enabling GL performance measurement");
- mPerfMeasurer = new PerfMeasurement();
- } else {
- Log.d(TAG, "GL performance measurement not supported on this device");
- mPerfMeasurer = null;
- }
- }
-
- private void beginGlTiming() {
- if (mPerfMeasurer == null) return;
- mPerfMeasurer.startTimer();
- }
-
- private void addGlTimestamp(long timestamp) {
- if (mPerfMeasurer == null) return;
- mPerfMeasurer.addTimestamp(timestamp);
- }
-
- private void endGlTiming() {
- if (mPerfMeasurer == null) return;
- mPerfMeasurer.stopTimer();
- }
-
- /**
- * Return the surface texture to draw to - this is the texture use to when producing output
- * surface buffers.
- *
- * @return a {@link SurfaceTexture}.
- */
- public SurfaceTexture getSurfaceTexture() {
- return mSurfaceTexture;
- }
-
- /**
- * Set a collection of output {@link Surface}s that can be drawn to.
- *
- * @param surfaces a {@link Collection} of surfaces.
- */
- public void configureSurfaces(Collection<Pair<Surface, Size>> surfaces) {
- releaseEGLContext();
-
- if (surfaces == null || surfaces.size() == 0) {
- Log.w(TAG, "No output surfaces configured for GL drawing.");
- return;
- }
-
- for (Pair<Surface, Size> p : surfaces) {
- Surface s = p.first;
- Size surfaceSize = p.second;
- // If pixel conversions aren't handled by egl, use a pbuffer
- try {
- EGLSurfaceHolder holder = new EGLSurfaceHolder();
- holder.surface = s;
- holder.width = surfaceSize.getWidth();
- holder.height = surfaceSize.getHeight();
- if (LegacyCameraDevice.needsConversion(s)) {
- mConversionSurfaces.add(holder);
- // LegacyCameraDevice is the producer of surfaces if it's not handled by EGL,
- // so LegacyCameraDevice needs to connect to the surfaces.
- LegacyCameraDevice.connectSurface(s);
- } else {
- mSurfaces.add(holder);
- }
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping configuration... ", e);
- }
- }
-
- // Set up egl display
- configureEGLContext();
-
- // Set up regular egl surfaces if needed
- if (mSurfaces.size() > 0) {
- configureEGLOutputSurfaces(mSurfaces);
- }
-
- // Set up pbuffer surface if needed
- if (mConversionSurfaces.size() > 0) {
- configureEGLPbufferSurfaces(mConversionSurfaces);
- }
-
- try {
- makeCurrent((mSurfaces.size() > 0) ? mSurfaces.get(0).eglSurface :
- mConversionSurfaces.get(0).eglSurface);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, skipping configuration... ", e);
- }
-
- initializeGLState();
- mSurfaceTexture = new SurfaceTexture(getTextureId());
-
- // Set up performance tracking if enabled
- if (SystemProperties.getBoolean(LEGACY_PERF_PROPERTY, false)) {
- setupGlTiming();
- }
- }
-
- /**
- * Draw the current buffer in the {@link SurfaceTexture} returned from
- * {@link #getSurfaceTexture()} into the set of target {@link Surface}s
- * in the next request from the given {@link CaptureCollector}, or drop
- * the frame if none is available.
- *
- * <p>
- * Any {@link Surface}s targeted must be a subset of the {@link Surface}s
- * set in the last {@link #configureSurfaces(java.util.Collection)} call.
- * </p>
- *
- * @param targetCollector the surfaces to draw to.
- */
- public void drawIntoSurfaces(CaptureCollector targetCollector) {
- if ((mSurfaces == null || mSurfaces.size() == 0)
- && (mConversionSurfaces == null || mConversionSurfaces.size() == 0)) {
- return;
- }
-
- boolean doTiming = targetCollector.hasPendingPreviewCaptures();
- checkGlError("before updateTexImage");
-
- if (doTiming) {
- beginGlTiming();
- }
-
- mSurfaceTexture.updateTexImage();
-
- long timestamp = mSurfaceTexture.getTimestamp();
-
- Pair<RequestHolder, Long> captureHolder = targetCollector.previewCaptured(timestamp);
-
- // No preview request queued, drop frame.
- if (captureHolder == null) {
- if (DEBUG) {
- Log.d(TAG, "Dropping preview frame.");
- }
- if (doTiming) {
- endGlTiming();
- }
- return;
- }
-
- RequestHolder request = captureHolder.first;
-
- Collection<Surface> targetSurfaces = request.getHolderTargets();
- if (doTiming) {
- addGlTimestamp(timestamp);
- }
-
- List<Long> targetSurfaceIds = new ArrayList();
- try {
- targetSurfaceIds = LegacyCameraDevice.getSurfaceIds(targetSurfaces);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, dropping frame. ", e);
- request.setOutputAbandoned();
- }
-
- for (EGLSurfaceHolder holder : mSurfaces) {
- if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
- try{
- LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
- holder.height);
- makeCurrent(holder.eglSurface);
-
- LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
- drawFrame(mSurfaceTexture, holder.width, holder.height,
- (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
- FLIP_TYPE_HORIZONTAL : FLIP_TYPE_NONE);
- swapBuffers(holder.eglSurface);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, dropping frame. ", e);
- request.setOutputAbandoned();
- }
- }
- }
- for (EGLSurfaceHolder holder : mConversionSurfaces) {
- if (LegacyCameraDevice.containsSurfaceId(holder.surface, targetSurfaceIds)) {
- // glReadPixels reads from the bottom of the buffer, so add an extra vertical flip
- try {
- makeCurrent(holder.eglSurface);
- drawFrame(mSurfaceTexture, holder.width, holder.height,
- (mFacing == CameraCharacteristics.LENS_FACING_FRONT) ?
- FLIP_TYPE_BOTH : FLIP_TYPE_VERTICAL);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- // Should never hit this.
- throw new IllegalStateException("Surface abandoned, skipping drawFrame...", e);
- }
- mPBufferPixels.clear();
- GLES20.glReadPixels(/*x*/ 0, /*y*/ 0, holder.width, holder.height,
- GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPBufferPixels);
- checkGlError("glReadPixels");
-
- try {
- int format = LegacyCameraDevice.detectSurfaceType(holder.surface);
- LegacyCameraDevice.setSurfaceDimens(holder.surface, holder.width,
- holder.height);
- LegacyCameraDevice.setNextTimestamp(holder.surface, captureHolder.second);
- LegacyCameraDevice.produceFrame(holder.surface, mPBufferPixels.array(),
- holder.width, holder.height, format);
- } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
- Log.w(TAG, "Surface abandoned, dropping frame. ", e);
- request.setOutputAbandoned();
- }
- }
- }
- targetCollector.previewProduced();
-
- if (doTiming) {
- endGlTiming();
- }
- }
-
- /**
- * Clean up the current GL context.
- */
- public void cleanupEGLContext() {
- releaseEGLContext();
- }
-
- /**
- * Drop all current GL operations on the floor.
- */
- public void flush() {
- // TODO: implement flush
- Log.e(TAG, "Flush not yet implemented.");
- }
-}
diff --git a/core/java/android/hardware/camera2/legacy/package.html b/core/java/android/hardware/camera2/legacy/package.html
deleted file mode 100644
index db6f78bbf628..000000000000
--- a/core/java/android/hardware/camera2/legacy/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<body>
-{@hide}
-</body> \ No newline at end of file
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index c37f9fe2465c..52251ba90b98 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -24,7 +24,6 @@ import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.legacy.LegacyCameraDevice;
import android.hardware.camera2.utils.HashCodeHelpers;
import android.hardware.camera2.utils.SurfaceUtils;
import android.util.Range;
@@ -69,6 +68,8 @@ public final class StreamConfigurationMap {
private static final String TAG = "StreamConfigurationMap";
+ private static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding
+
/**
* Create a new {@link StreamConfigurationMap}.
*
@@ -568,7 +569,7 @@ public final class StreamConfigurationMap {
if (config.getSize().equals(surfaceSize)) {
return true;
} else if (isFlexible &&
- (config.getSize().getWidth() <= LegacyCameraDevice.MAX_DIMEN_FOR_ROUNDING)) {
+ (config.getSize().getWidth() <= MAX_DIMEN_FOR_ROUNDING)) {
return true;
}
}
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index abe1372ebde4..35b5c1599070 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -16,10 +16,14 @@
package android.hardware.camera2.utils;
+import static android.system.OsConstants.EINVAL;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.ImageFormat;
-import android.hardware.camera2.legacy.LegacyCameraDevice;
-import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
+import android.graphics.PixelFormat;
+import android.hardware.HardwareBuffer;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.util.Range;
import android.util.Size;
@@ -35,6 +39,15 @@ import java.util.List;
*/
public class SurfaceUtils {
+ // Usage flags not yet included in HardwareBuffer
+ private static final int USAGE_RENDERSCRIPT = 0x00100000;
+ private static final int USAGE_HW_COMPOSER = 0x00000800;
+
+ // Image formats not yet included in PixelFormat
+ private static final int BGRA_8888 = 0x5;
+
+ private static final int BAD_VALUE = -EINVAL;
+
/**
* Check if a surface is for preview consumer based on consumer end point Gralloc usage flags.
*
@@ -42,7 +55,17 @@ public class SurfaceUtils {
* @return true if the surface is for preview consumer, false otherwise.
*/
public static boolean isSurfaceForPreview(Surface surface) {
- return LegacyCameraDevice.isPreviewConsumer(surface);
+ checkNotNull(surface);
+ long usageFlags = nativeDetectSurfaceUsageFlags(surface);
+ long disallowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE | USAGE_RENDERSCRIPT
+ | HardwareBuffer.USAGE_CPU_READ_OFTEN;
+ long allowedFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | USAGE_HW_COMPOSER
+ | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT;
+ boolean previewConsumer = ((usageFlags & disallowedFlags) == 0
+ && (usageFlags & allowedFlags) != 0);
+ int surfaceFormat = getSurfaceFormat(surface);
+
+ return previewConsumer;
}
/**
@@ -53,7 +76,17 @@ public class SurfaceUtils {
* @return true if the surface is for hardware video encoder consumer, false otherwise.
*/
public static boolean isSurfaceForHwVideoEncoder(Surface surface) {
- return LegacyCameraDevice.isVideoEncoderConsumer(surface);
+ checkNotNull(surface);
+ long usageFlags = nativeDetectSurfaceUsageFlags(surface);
+ long disallowedFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE | USAGE_HW_COMPOSER
+ | USAGE_RENDERSCRIPT | HardwareBuffer.USAGE_CPU_READ_OFTEN;
+ long allowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE;
+ boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0
+ && (usageFlags & allowedFlags) != 0);
+
+ int surfaceFormat = getSurfaceFormat(surface);
+
+ return videoEncoderConsumer;
}
/**
@@ -63,9 +96,10 @@ public class SurfaceUtils {
* @return the native object id of the surface, 0 if surface is not backed by a native object.
*/
public static long getSurfaceId(Surface surface) {
+ checkNotNull(surface);
try {
- return LegacyCameraDevice.getSurfaceId(surface);
- } catch (BufferQueueAbandonedException e) {
+ return nativeGetSurfaceId(surface);
+ } catch (IllegalArgumentException e) {
return 0;
}
}
@@ -80,11 +114,13 @@ public class SurfaceUtils {
*/
@UnsupportedAppUsage
public static Size getSurfaceSize(Surface surface) {
- try {
- return LegacyCameraDevice.getSurfaceSize(surface);
- } catch (BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Surface was abandoned", e);
- }
+ checkNotNull(surface);
+
+ int[] dimens = new int[2];
+ int errorFlag = nativeDetectSurfaceDimens(surface, /*out*/dimens);
+ if (errorFlag == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned");
+
+ return new Size(dimens[0], dimens[1]);
}
/**
@@ -96,11 +132,17 @@ public class SurfaceUtils {
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public static int getSurfaceFormat(Surface surface) {
- try {
- return LegacyCameraDevice.detectSurfaceType(surface);
- } catch (BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Surface was abandoned", e);
+ checkNotNull(surface);
+ int surfaceType = nativeDetectSurfaceType(surface);
+ if (surfaceType == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned");
+
+ // TODO: remove this override since the default format should be
+ // ImageFormat.PRIVATE. b/9487482
+ if ((surfaceType >= PixelFormat.RGBA_8888
+ && surfaceType <= BGRA_8888)) {
+ surfaceType = ImageFormat.PRIVATE;
}
+ return surfaceType;
}
/**
@@ -112,11 +154,10 @@ public class SurfaceUtils {
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public static int getSurfaceDataspace(Surface surface) {
- try {
- return LegacyCameraDevice.detectSurfaceDataspace(surface);
- } catch (BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Surface was abandoned", e);
- }
+ checkNotNull(surface);
+ int dataSpace = nativeDetectSurfaceDataspace(surface);
+ if (dataSpace == BAD_VALUE) throw new IllegalArgumentException("Surface was abandoned");
+ return dataSpace;
}
/**
@@ -125,9 +166,21 @@ public class SurfaceUtils {
*
*/
public static boolean isFlexibleConsumer(Surface output) {
- return LegacyCameraDevice.isFlexibleConsumer(output);
+ checkNotNull(output);
+ long usageFlags = nativeDetectSurfaceUsageFlags(output);
+
+ // Keep up to date with allowed consumer types in
+ // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+ long disallowedFlags = HardwareBuffer.USAGE_VIDEO_ENCODE | USAGE_RENDERSCRIPT;
+ long allowedFlags = HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
+ | HardwareBuffer.USAGE_CPU_READ_OFTEN
+ | USAGE_HW_COMPOSER;
+ boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0
+ && (usageFlags & allowedFlags) != 0);
+ return flexibleConsumer;
}
+
/**
* A high speed output surface can only be preview or hardware encoder surface.
*
@@ -209,4 +262,14 @@ public class SurfaceUtils {
}
}
+ private static native int nativeDetectSurfaceType(Surface surface);
+
+ private static native int nativeDetectSurfaceDataspace(Surface surface);
+
+ private static native long nativeDetectSurfaceUsageFlags(Surface surface);
+
+ private static native int nativeDetectSurfaceDimens(Surface surface,
+ /*out*/int[/*2*/] dimens);
+
+ private static native long nativeGetSurfaceId(Surface surface);
}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index b4546a49a07c..308718f3871b 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -70,11 +70,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
private static final int MSG_GET_FEATURE_COMPLETED = 106;
private static final int MSG_SET_FEATURE_COMPLETED = 107;
private static final int MSG_CHALLENGE_GENERATED = 108;
+ private static final int MSG_FACE_DETECTED = 109;
- private IFaceService mService;
+ private final IFaceService mService;
private final Context mContext;
private IBinder mToken = new Binder();
private AuthenticationCallback mAuthenticationCallback;
+ private FaceDetectionCallback mFaceDetectionCallback;
private EnrollmentCallback mEnrollmentCallback;
private RemovalCallback mRemovalCallback;
private SetFeatureCallback mSetFeatureCallback;
@@ -103,6 +105,12 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
@Override // binder call
+ public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
+ mHandler.obtainMessage(MSG_FACE_DETECTED, sensorId, userId, isStrongBiometric)
+ .sendToTarget();
+ }
+
+ @Override // binder call
public void onAuthenticationFailed() {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
}
@@ -251,6 +259,34 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
+ * Uses the face hardware to detect for the presence of a face, without giving details about
+ * accept/reject/lockout.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void detectFace(@NonNull CancellationSignal cancel,
+ @NonNull FaceDetectionCallback callback, int userId) {
+ if (mService == null) {
+ return;
+ }
+
+ if (cancel.isCanceled()) {
+ Slog.w(TAG, "Detection already cancelled");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
+ }
+
+ mFaceDetectionCallback = callback;
+
+ try {
+ mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception when requesting finger detect", e);
+ }
+ }
+
+ /**
* Defaults to {@link FaceManager#enroll(int, byte[], CancellationSignal, EnrollmentCallback,
* int[], Surface)} with {@code surface} set to null.
*
@@ -581,6 +617,24 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
+ * Get statically configured sensor properties.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ @NonNull
+ public FaceSensorProperties getSensorProperties() {
+ try {
+ if (mService == null || !mService.isHardwareDetected(mContext.getOpPackageName())) {
+ return new FaceSensorProperties();
+ }
+ return mService.getSensorProperties(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return new FaceSensorProperties();
+ }
+
+ /**
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -639,6 +693,18 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
}
+ private void cancelFaceDetect() {
+ if (mService == null) {
+ return;
+ }
+
+ try {
+ mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* @hide
*/
@@ -896,6 +962,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
/**
+ * @hide
+ */
+ public interface FaceDetectionCallback {
+ void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric);
+ }
+
+ /**
* Callback structure provided to {@link FaceManager#enroll(long,
* EnrollmentCallback, CancellationSignal, int). Users of {@link #FaceAuthenticationManager()}
* must provide an implementation of this to {@link FaceManager#enroll(long,
@@ -1026,6 +1099,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
}
}
+ private class OnFaceDetectionCancelListener implements OnCancelListener {
+ @Override
+ public void onCancel() {
+ cancelFaceDetect();
+ }
+ }
+
private class MyHandler extends Handler {
private MyHandler(Context context) {
super(context.getMainLooper());
@@ -1072,6 +1152,10 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
case MSG_CHALLENGE_GENERATED:
sendChallengeGenerated((long) msg.obj /* challenge */);
break;
+ case MSG_FACE_DETECTED:
+ sendFaceDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
+ (boolean) msg.obj /* isStrongBiometric */);
+ break;
default:
Slog.w(TAG, "Unknown message: " + msg.what);
}
@@ -1100,6 +1184,14 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
mGenerateChallengeCallback.onGenerateChallengeResult(challenge);
}
+ private void sendFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
+ if (mFaceDetectionCallback == null) {
+ Slog.e(TAG, "sendFaceDetected, callback null");
+ return;
+ }
+ mFaceDetectionCallback.onFaceDetected(sensorId, userId, isStrongBiometric);
+ }
+
private void sendRemovedResult(Face face, int remaining) {
if (mRemovalCallback == null) {
return;
diff --git a/core/java/android/hardware/face/FaceSensorProperties.aidl b/core/java/android/hardware/face/FaceSensorProperties.aidl
new file mode 100644
index 000000000000..d83ee4b17fa7
--- /dev/null
+++ b/core/java/android/hardware/face/FaceSensorProperties.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.face;
+
+parcelable FaceSensorProperties; \ No newline at end of file
diff --git a/core/java/android/hardware/face/FaceSensorProperties.java b/core/java/android/hardware/face/FaceSensorProperties.java
new file mode 100644
index 000000000000..28c1d8772506
--- /dev/null
+++ b/core/java/android/hardware/face/FaceSensorProperties.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.face;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for face sensor properties.
+ * @hide
+ */
+public class FaceSensorProperties implements Parcelable {
+
+ public final boolean supportsFaceDetection;
+
+ /**
+ * Creates a SensorProperties class with safe default values
+ */
+ public FaceSensorProperties() {
+ supportsFaceDetection = false;
+ }
+
+ /**
+ * Initializes SensorProperties with specified values
+ */
+ public FaceSensorProperties(boolean supportsFaceDetection) {
+ this.supportsFaceDetection = supportsFaceDetection;
+ }
+
+ protected FaceSensorProperties(Parcel in) {
+ supportsFaceDetection = in.readBoolean();
+ }
+
+ public static final Creator<FaceSensorProperties> CREATOR =
+ new Creator<FaceSensorProperties>() {
+ @Override
+ public FaceSensorProperties createFromParcel(Parcel in) {
+ return new FaceSensorProperties(in);
+ }
+
+ @Override
+ public FaceSensorProperties[] newArray(int size) {
+ return new FaceSensorProperties[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(supportsFaceDetection);
+ }
+}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 2f8c97f8022d..5d5fe4e270a1 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -19,6 +19,7 @@ import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
import android.hardware.face.IFaceServiceReceiver;
import android.hardware.face.Face;
+import android.hardware.face.FaceSensorProperties;
import android.view.Surface;
/**
@@ -31,6 +32,10 @@ interface IFaceService {
void authenticate(IBinder token, long operationId, int userid, IFaceServiceReceiver receiver,
String opPackageName);
+ // Uses the face hardware to detect for the presence of a face, without giving details
+ // about accept/reject/lockout.
+ void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
+
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
// called from BiometricService. The additional uid, pid, userId arguments should be determined
@@ -46,6 +51,9 @@ interface IFaceService {
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel face detection
+ void cancelFaceDetect(IBinder token, String opPackageName);
+
// Same as above, with extra arguments.
void cancelAuthenticationFromService(IBinder token, String opPackageName,
int callingUid, int callingPid, int callingUserId);
@@ -80,6 +88,9 @@ interface IFaceService {
// Determine if a user has at least one enrolled face
boolean hasEnrolledFaces(int userId, String opPackageName);
+ // Retrieve static sensor properties
+ FaceSensorProperties getSensorProperties(String opPackageName);
+
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int userId);
diff --git a/core/java/android/hardware/face/IFaceServiceReceiver.aidl b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
index 844657e7453f..2600b7def03a 100644
--- a/core/java/android/hardware/face/IFaceServiceReceiver.aidl
+++ b/core/java/android/hardware/face/IFaceServiceReceiver.aidl
@@ -25,6 +25,7 @@ oneway interface IFaceServiceReceiver {
void onEnrollResult(in Face face, int remaining);
void onAcquired(int acquiredInfo, int vendorCode);
void onAuthenticationSucceeded(in Face face, int userId, boolean isStrongBiometric);
+ void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric);
void onAuthenticationFailed();
void onError(int error, int vendorCode);
void onRemoved(in Face face, int remaining);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 4ca75d9a09cf..8488454933da 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,7 @@ package android.hardware.fingerprint;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.USE_BIOMETRIC;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import android.annotation.NonNull;
@@ -65,6 +66,7 @@ import javax.crypto.Mac;
* it's much more realistic to have a system-provided authentication dialog since the method may
* vary by vendor/device.
*/
+@SuppressWarnings("deprecation")
@Deprecated
@SystemService(Context.FINGERPRINT_SERVICE)
@RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
@@ -79,11 +81,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private static final int MSG_ERROR = 104;
private static final int MSG_REMOVED = 105;
private static final int MSG_CHALLENGE_GENERATED = 106;
+ private static final int MSG_FINGERPRINT_DETECTED = 107;
private IFingerprintService mService;
private Context mContext;
private IBinder mToken = new Binder();
private AuthenticationCallback mAuthenticationCallback;
+ private FingerprintDetectionCallback mFingerprintDetectionCallback;
private EnrollmentCallback mEnrollmentCallback;
private RemovalCallback mRemovalCallback;
private GenerateChallengeCallback mGenerateChallengeCallback;
@@ -111,6 +115,13 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ private class OnFingerprintDetectionCancelListener implements OnCancelListener {
+ @Override
+ public void onCancel() {
+ cancelFingerprintDetect();
+ }
+ }
+
/**
* A wrapper class for the crypto objects supported by FingerprintManager. Currently the
* framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
@@ -221,7 +232,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
public boolean isStrongBiometric() {
return mIsStrongBiometric;
}
- };
+ }
/**
* Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
@@ -273,7 +284,19 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@Override
public void onAuthenticationAcquired(int acquireInfo) {}
- };
+ }
+
+ /**
+ * Callback structure provided for {@link #detectFingerprint(CancellationSignal,
+ * FingerprintDetectionCallback, int, Surface)}.
+ * @hide
+ */
+ public interface FingerprintDetectionCallback {
+ /**
+ * Invoked when a fingerprint has been detected.
+ */
+ void onFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric);
+ }
/**
* Callback structure provided to {@link FingerprintManager#enroll(byte[], CancellationSignal,
@@ -308,7 +331,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* @param remaining The number of remaining steps
*/
public void onEnrollmentProgress(int remaining) { }
- };
+ }
/**
* Callback structure provided to {@link #remove}. Users of {@link FingerprintManager} may
@@ -336,7 +359,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* fingerprints in the group, and 0 after the last fingerprint is removed.
*/
public void onRemovalSucceeded(Fingerprint fp, int remaining) { }
- };
+ }
/**
* @hide
@@ -348,7 +371,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
* again.
*/
public void onLockoutReset(int sensorId) { }
- };
+ }
/**
* @hide
@@ -463,6 +486,35 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
+ * Uses the fingerprint hardware to detect for the presence of a finger, without giving details
+ * about accept/reject/lockout.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void detectFingerprint(@NonNull CancellationSignal cancel,
+ @NonNull FingerprintDetectionCallback callback, int userId, @Nullable Surface surface) {
+ if (mService == null) {
+ return;
+ }
+
+ if (cancel.isCanceled()) {
+ Slog.w(TAG, "Detection already cancelled");
+ return;
+ } else {
+ cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
+ }
+
+ mFingerprintDetectionCallback = callback;
+
+ try {
+ mService.detectFingerprint(mToken, userId, mServiceReceiver,
+ mContext.getOpPackageName(), surface);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Remote exception when requesting finger detect", e);
+ }
+ }
+
+ /**
* Defaults to {@link FingerprintManager#enroll(byte[], CancellationSignal, int,
* EnrollmentCallback, Surface)} with {@code surface} set to null.
*
@@ -685,6 +737,75 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
/**
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public boolean isUdfps() {
+ if (mService == null) {
+ Slog.w(TAG, "isUdfps: no fingerprint service");
+ return false;
+ }
+
+ try {
+ return mService.isUdfps();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void setUdfpsOverlayController(IUdfpsOverlayController controller) {
+ if (mService == null) {
+ Slog.w(TAG, "setUdfpsOverlayController: no fingerprint service");
+ return;
+ }
+
+ try {
+ mService.setUdfpsOverlayController(controller);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onFingerDown(int x, int y, float minor, float major) {
+ if (mService == null) {
+ Slog.w(TAG, "onFingerDown: no fingerprint service");
+ return;
+ }
+
+ try {
+ mService.onFingerDown(x, y, minor, major);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onFingerUp() {
+ if (mService == null) {
+ Slog.w(TAG, "onFingerDown: no fingerprint service");
+ return;
+ }
+
+ try {
+ mService.onFingerUp();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Determine if there is at least one fingerprint enrolled.
*
* @return true if at least one fingerprint is enrolled, false otherwise
@@ -812,12 +933,16 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
case MSG_CHALLENGE_GENERATED:
sendChallengeGenerated((long) msg.obj /* challenge */);
break;
+ case MSG_FINGERPRINT_DETECTED:
+ sendFingerprintDetected(msg.arg1 /* sensorId */, msg.arg2 /* userId */,
+ (boolean) msg.obj /* isStrongBiometric */);
+ break;
default:
Slog.w(TAG, "Unknown message: " + msg.what);
}
}
- };
+ }
private void sendRemovedResult(Fingerprint fingerprint, int remaining) {
if (mRemovalCallback == null) {
@@ -902,6 +1027,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
mGenerateChallengeCallback.onChallengeGenerated(challenge);
}
+ private void sendFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric) {
+ if (mFingerprintDetectionCallback == null) {
+ Slog.e(TAG, "sendFingerprintDetected, callback null");
+ return;
+ }
+ mFingerprintDetectionCallback.onFingerprintDetected(sensorId, userId, isStrongBiometric);
+ }
+
/**
* @hide
*/
@@ -938,6 +1071,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ private void cancelFingerprintDetect() {
+ if (mService == null) {
+ return;
+ }
+
+ try {
+ mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/**
* @hide
*/
@@ -1041,6 +1186,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
fp).sendToTarget();
}
+ @Override
+ public void onFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric) {
+ mHandler.obtainMessage(MSG_FINGERPRINT_DETECTED, sensorId, userId, isStrongBiometric)
+ .sendToTarget();
+ }
+
@Override // binder call
public void onAuthenticationFailed() {
mHandler.obtainMessage(MSG_AUTHENTICATION_FAILED).sendToTarget();
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 38d7d2bc9e27..3604b5e8671d 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -35,6 +35,11 @@ interface IFingerprintService {
void authenticate(IBinder token, long operationId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName, in Surface surface);
+ // Uses the fingerprint hardware to detect for the presence of a finger, without giving details
+ // about accept/reject/lockout.
+ void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
+ String opPackageName, in Surface surface);
+
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
// called from BiometricService. The additional uid, pid, userId arguments should be determined
@@ -50,6 +55,9 @@ interface IFingerprintService {
// Cancel authentication for the given sessionId
void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel finger detection
+ void cancelFingerprintDetect(IBinder token, String opPackageName);
+
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid.
void cancelAuthenticationFromService(IBinder token, String opPackageName,
@@ -114,8 +122,8 @@ interface IFingerprintService {
// Notifies about a finger leaving the sensor area.
void onFingerUp();
- // Returns whether the specified sensor is an under-display fingerprint sensor (UDFPS).
- boolean isUdfps(int sensorId);
+ // Returns whether the sensor is an under-display fingerprint sensor (UDFPS).
+ boolean isUdfps();
// Sets the controller for managing the UDFPS overlay.
void setUdfpsOverlayController(in IUdfpsOverlayController controller);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index 3da07b05efb6..ad8fbc087ed0 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -25,6 +25,7 @@ oneway interface IFingerprintServiceReceiver {
void onEnrollResult(in Fingerprint fp, int remaining);
void onAcquired(int acquiredInfo, int vendorCode);
void onAuthenticationSucceeded(in Fingerprint fp, int userId, boolean isStrongBiometric);
+ void onFingerprintDetected(int sensorId, int userId, boolean isStrongBiometric);
void onAuthenticationFailed();
void onError(int error, int vendorCode);
void onRemoved(in Fingerprint fp, int remaining);
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index eba7ff348328..7234eb1d81cd 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable {
* @hide
*/
public static final int NETWORK_TYPE_ALL = -1;
+ /**
+ * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is
+ * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along
+ * with NR state as connected. This should not be overlapped with any of the
+ * {@code TelephonyManager.NETWORK_TYPE_*} constants.
+ *
+ * @hide
+ */
+ public static final int NETWORK_TYPE_5G_NSA = -2;
private static boolean isKnownMatchRule(final int rule) {
switch (rule) {
@@ -475,6 +484,9 @@ public class NetworkTemplate implements Parcelable {
return TelephonyManager.NETWORK_TYPE_LTE;
case TelephonyManager.NETWORK_TYPE_NR:
return TelephonyManager.NETWORK_TYPE_NR;
+ // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+ case NetworkTemplate.NETWORK_TYPE_5G_NSA:
+ return NetworkTemplate.NETWORK_TYPE_5G_NSA;
default:
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ffe9ae9521a8..a32b41f6be4b 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -127,18 +127,6 @@ public class ProxyInfo implements Parcelable {
}
/**
- * Create a ProxyProperties that points at a PAC URL.
- * @hide
- */
- public ProxyInfo(String pacFileUrl) {
- mHost = LOCAL_HOST;
- mPort = LOCAL_PORT;
- mExclusionList = LOCAL_EXCL_LIST;
- mParsedExclusionList = parseExclusionList(mExclusionList);
- mPacFileUrl = Uri.parse(pacFileUrl);
- }
-
- /**
* Only used in PacManager after Local Proxy is bound.
* @hide
*/
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 18ba5a8a4a34..bb8d4fe19aa2 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -375,7 +375,8 @@ public class DropBoxManager {
@RequiresPermission(allOf = { READ_LOGS, PACKAGE_USAGE_STATS })
public @Nullable Entry getNextEntry(String tag, long msec) {
try {
- return mService.getNextEntry(tag, msec, mContext.getOpPackageName());
+ return mService.getNextEntryWithAttribution(tag, msec, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
} catch (SecurityException e) {
if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.P) {
throw e;
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index dea932dd6178..17a78a8f301e 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIE
import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
import static android.permission.PermissionControllerService.SERVICE_INTERFACE;
+import static com.android.internal.util.FunctionalUtils.uncheckExceptions;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
@@ -56,6 +57,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.RemoteStream;
import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import libcore.util.EmptyArray;
@@ -208,8 +210,15 @@ public final class PermissionControllerManager {
ServiceConnector<IPermissionController> remoteService = sRemoteServices.get(key);
if (remoteService == null) {
Intent intent = new Intent(SERVICE_INTERFACE);
- intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
+ String pkgName = context.getPackageManager().getPermissionControllerPackageName();
+ intent.setPackage(pkgName);
ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);
+ if (serviceInfo == null) {
+ String errorMsg = "No PermissionController package (" + pkgName + ") for user "
+ + context.getUserId();
+ Log.wtf(TAG, errorMsg);
+ throw new IllegalStateException(errorMsg);
+ }
remoteService = new ServiceConnector.Impl<IPermissionController>(
ActivityThread.currentApplication() /* context */,
new Intent(SERVICE_INTERFACE)
@@ -490,8 +499,11 @@ public final class PermissionControllerManager {
*/
public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) {
try {
- mRemoteService.post(service -> service.asBinder().dump(fd, args))
- .get(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ mRemoteService.postAsync(service -> {
+ return AndroidFuture.runAsync(uncheckExceptions(() -> {
+ service.asBinder().dump(fd, args);
+ }), BackgroundThread.getExecutor());
+ }).get(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
} catch (Exception e) {
Log.e(TAG, "Could not get dump", e);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index feebb9485167..e1d48860b1e2 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8298,6 +8298,13 @@ public final class Settings {
public static final String CAMERA_GESTURE_DISABLED = "camera_gesture_disabled";
/**
+ * Whether the panic button (emergency sos) gesture should be enabled.
+ *
+ * @hide
+ */
+ public static final String PANIC_GESTURE_ENABLED = "panic_gesture_enabled";
+
+ /**
* Whether the camera launch gesture to double tap the power button when the screen is off
* should be disabled.
*
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index fae26cf77c16..9f52142a5109 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1357,8 +1357,7 @@ public final class Telephony {
Object[] messages;
try {
messages = (Object[]) intent.getSerializableExtra("pdus");
- }
- catch (ClassCastException e) {
+ } catch (ClassCastException e) {
Rlog.e(TAG, "getMessagesFromIntent: " + e);
return null;
}
@@ -1370,9 +1369,12 @@ public final class Telephony {
String format = intent.getStringExtra("format");
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
- SubscriptionManager.getDefaultSmsSubscriptionId());
-
- Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Rlog.v(TAG, "getMessagesFromIntent with valid subId : " + subId);
+ } else {
+ Rlog.v(TAG, "getMessagesFromIntent");
+ }
int pduCount = messages.length;
SmsMessage[] msgs = new SmsMessage[pduCount];
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 31da83ad5137..69220722fc05 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -308,7 +308,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
false /* isScreenRound */,
false /* alwaysConsumeSystemBars */, null /* displayCutout */,
LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/,
- 0 /* legacySystemUiFlags */, typeSideMap)
+ 0 /* legacyWindowFlags */, 0 /* legacySystemUiFlags */, typeSideMap)
.getInsets(mTypes);
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index a679b3740fd9..c383bc7a4d70 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -501,6 +501,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private PendingControlRequest mPendingImeControlRequest;
private int mLastLegacySoftInputMode;
+ private int mLastLegacyWindowFlags;
private int mLastLegacySystemUiFlags;
private DisplayCutout mLastDisplayCutout;
private boolean mStartingAnimation;
@@ -569,8 +570,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
WindowInsets insets = state.calculateInsets(mFrame, mState /* ignoringVisibilityState*/,
mLastInsets.isRound(), mLastInsets.shouldAlwaysConsumeSystemBars(),
- mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags,
- null /* typeSideMap */);
+ mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacyWindowFlags,
+ mLastLegacySystemUiFlags, null /* typeSideMap */);
mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims);
if (DEBUG) {
for (WindowInsetsAnimation anim : mUnmodifiableTmpRunningAnims) {
@@ -706,13 +707,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public WindowInsets calculateInsets(boolean isScreenRound,
boolean alwaysConsumeSystemBars, DisplayCutout cutout,
- int legacySoftInputMode, int legacySystemUiFlags) {
+ int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags) {
mLastLegacySoftInputMode = legacySoftInputMode;
+ mLastLegacyWindowFlags = legacyWindowFlags;
mLastLegacySystemUiFlags = legacySystemUiFlags;
mLastDisplayCutout = cutout;
mLastInsets = mState.calculateInsets(mFrame, null /* ignoringVisibilityState*/,
isScreenRound, alwaysConsumeSystemBars, cutout,
- legacySoftInputMode, legacySystemUiFlags,
+ legacySoftInputMode, legacyWindowFlags, legacySystemUiFlags,
null /* typeSideMap */);
return mLastInsets;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 91e7591193f1..6b0b509932a8 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -22,13 +22,14 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
-import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.indexOf;
import static android.view.WindowInsets.Type.isVisibleInsetsType;
+import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowInsets.Type.systemBars;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -38,7 +39,6 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;
@@ -171,7 +171,7 @@ public class InsetsState implements Parcelable {
*/
public WindowInsets calculateInsets(Rect frame, @Nullable InsetsState ignoringVisibilityState,
boolean isScreenRound, boolean alwaysConsumeSystemBars, DisplayCutout cutout,
- int legacySoftInputMode, int legacySystemUiFlags,
+ int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
Insets[] typeInsetsMap = new Insets[Type.SIZE];
Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
@@ -218,10 +218,17 @@ public class InsetsState implements Parcelable {
}
}
final int softInputAdjustMode = legacySoftInputMode & SOFT_INPUT_MASK_ADJUST;
+
+ @InsetsType int compatInsetsTypes = systemBars() | displayCutout();
+ if (softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE) {
+ compatInsetsTypes |= ime();
+ }
+ if ((legacyWindowFlags & FLAG_FULLSCREEN) != 0) {
+ compatInsetsTypes &= ~statusBars();
+ }
+
return new WindowInsets(typeInsetsMap, typeMaxInsetsMap, typeVisibilityMap, isScreenRound,
- alwaysConsumeSystemBars, cutout, softInputAdjustMode == SOFT_INPUT_ADJUST_RESIZE
- ? systemBars() | displayCutout() | ime()
- : systemBars() | displayCutout(),
+ alwaysConsumeSystemBars, cutout, compatInsetsTypes,
sNewInsetsMode == NEW_INSETS_MODE_FULL
&& (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2168fe331972..4e63a3392d48 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3506,6 +3506,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT
* 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK
* 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED
+ * 1 PFLAG4_DETACHED
* |-------|-------|-------|-------|
*/
@@ -3567,6 +3568,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
*/
private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000;
+ /**
+ * Indicates if the view is just detached.
+ */
+ private static final int PFLAG4_DETACHED = 0x000002000;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -4323,9 +4329,46 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
equals = STATUS_BAR_TRANSPARENT,
name = "STATUS_BAR_TRANSPARENT")
}, formatToHexString = true)
+ @SystemUiVisibility
int mSystemUiVisibility;
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "", value = {
+ SYSTEM_UI_FLAG_LOW_PROFILE,
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_FULLSCREEN,
+ SYSTEM_UI_FLAG_LAYOUT_STABLE,
+ SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION,
+ SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN,
+ SYSTEM_UI_FLAG_IMMERSIVE,
+ SYSTEM_UI_FLAG_IMMERSIVE_STICKY,
+ SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ STATUS_BAR_DISABLE_EXPAND,
+ STATUS_BAR_DISABLE_NOTIFICATION_ICONS,
+ STATUS_BAR_DISABLE_NOTIFICATION_ALERTS,
+ STATUS_BAR_DISABLE_NOTIFICATION_TICKER,
+ STATUS_BAR_DISABLE_SYSTEM_INFO,
+ STATUS_BAR_DISABLE_HOME,
+ STATUS_BAR_DISABLE_BACK,
+ STATUS_BAR_DISABLE_CLOCK,
+ STATUS_BAR_DISABLE_RECENT,
+ STATUS_BAR_DISABLE_SEARCH,
+ STATUS_BAR_TRANSIENT,
+ NAVIGATION_BAR_TRANSIENT,
+ STATUS_BAR_UNHIDE,
+ NAVIGATION_BAR_UNHIDE,
+ STATUS_BAR_TRANSLUCENT,
+ NAVIGATION_BAR_TRANSLUCENT,
+ NAVIGATION_BAR_TRANSPARENT,
+ STATUS_BAR_TRANSPARENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SystemUiVisibility {}
+
+ /**
* Reference count for transient state.
* @see #setHasTransientState(boolean)
*/
@@ -8330,7 +8373,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
(event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes()
& AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0);
- if (!isShown() && !isWindowDisappearedEvent) {
+ boolean detached = detached();
+ if (!isShown() && !isWindowDisappearedEvent && !detached) {
return;
}
onInitializeAccessibilityEvent(event);
@@ -8341,6 +8385,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event);
if (throttle != null) {
throttle.post(event);
+ } else if (!isWindowDisappearedEvent && detached) {
+ // Views could be attached soon later. Accessibility events during this temporarily
+ // detached period should be sent too.
+ postDelayed(() -> {
+ if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) {
+ requestParentSendAccessibilityEvent(event);
+ }
+ }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
} else {
requestParentSendAccessibilityEvent(event);
}
@@ -11126,6 +11178,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return false;
}
+ private boolean detached() {
+ View current = this;
+ //noinspection ConstantConditions
+ do {
+ if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) {
+ return true;
+ }
+ ViewParent parent = current.mParent;
+ if (parent == null) {
+ return false;
+ }
+ if (!(parent instanceof View)) {
+ return false;
+ }
+ current = (View) parent;
+ } while (current != null);
+
+ return false;
+ }
+
/**
* Called by the view hierarchy when the content insets for a window have
* changed, to allow it to adjust its content to fit within those windows.
@@ -29460,7 +29532,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
@Override
public void run() {
- if (AccessibilityManager.getInstance(mContext).isEnabled()) {
+ if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) {
requestParentSendAccessibilityEvent(mAccessibilityEvent);
}
reset();
@@ -30449,4 +30521,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
}
+
+ /**
+ * Set the view to be detached or not detached.
+ *
+ * @param detached Whether the view is detached.
+ *
+ * @hide
+ */
+ protected void setDetached(boolean detached) {
+ if (detached) {
+ mPrivateFlags4 |= PFLAG4_DETACHED;
+ } else {
+ mPrivateFlags4 &= ~PFLAG4_DETACHED;
+ }
+ }
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 05b75e4f0d41..4a37f8005c65 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5811,6 +5811,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
& ~PFLAG_DRAWING_CACHE_VALID)
| PFLAG_DRAWN | PFLAG_INVALIDATED;
+ child.setDetached(false);
this.mPrivateFlags |= PFLAG_INVALIDATED;
if (child.hasFocus()) {
@@ -5839,6 +5840,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @see #removeDetachedView(View, boolean)
*/
protected void detachViewFromParent(View child) {
+ child.setDetached(true);
removeFromArray(indexOfChild(child));
}
@@ -5860,6 +5862,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @see #removeDetachedView(View, boolean)
*/
protected void detachViewFromParent(int index) {
+ if (index >= 0 && index < mChildrenCount) {
+ mChildren[index].setDetached(true);
+ }
removeFromArray(index);
}
@@ -5882,6 +5887,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @see #removeDetachedView(View, boolean)
*/
protected void detachViewsFromParent(int start, int count) {
+ start = Math.max(0, start);
+ final int end = Math.min(mChildrenCount, start + count);
+ for (int i = start; i < end; i++) {
+ mChildren[i].setDetached(true);
+ }
removeFromArray(start, count);
}
@@ -5911,6 +5921,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
for (int i = count - 1; i >= 0; i--) {
children[i].mParent = null;
+ children[i].setDetached(true);
children[i] = null;
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f2cec250d47f..fe6f33da6d2a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2257,7 +2257,8 @@ public final class ViewRootImpl implements ViewParent,
mLastWindowInsets = mInsetsController.calculateInsets(
mContext.getResources().getConfiguration().isScreenRound(),
mAttachInfo.mAlwaysConsumeSystemBars, mPendingDisplayCutout.get(),
- mWindowAttributes.softInputMode, (mWindowAttributes.systemUiVisibility
+ mWindowAttributes.softInputMode, mWindowAttributes.flags,
+ (mWindowAttributes.systemUiVisibility
| mWindowAttributes.subtreeSystemUiVisibility));
Rect visibleInsets = mInsetsController.calculateVisibleInsets(
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 4d6b72f96aab..5e94758b003c 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -17,7 +17,6 @@
package android.view;
-import static android.view.WindowInsets.Type.CAPTION_BAR;
import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
@@ -95,7 +94,7 @@ public final class WindowInsets {
private final boolean mStableInsetsConsumed;
private final boolean mDisplayCutoutConsumed;
- private final int mCompatInsetTypes;
+ private final int mCompatInsetsTypes;
private final boolean mCompatIgnoreVisibility;
/**
@@ -150,8 +149,8 @@ public final class WindowInsets {
@Nullable Insets[] typeMaxInsetsMap,
boolean[] typeVisibilityMap,
boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout, int compatInsetTypes,
- boolean compatIgnoreVisibility) {
+ boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
+ @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
? new Insets[SIZE]
@@ -165,7 +164,7 @@ public final class WindowInsets {
mTypeVisibilityMap = typeVisibilityMap;
mIsRound = isRound;
mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
- mCompatInsetTypes = compatInsetTypes;
+ mCompatInsetsTypes = compatInsetsTypes;
mCompatIgnoreVisibility = compatIgnoreVisibility;
mDisplayCutoutConsumed = displayCutout == null;
@@ -183,7 +182,7 @@ public final class WindowInsets {
src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
src.mTypeVisibilityMap, src.mIsRound,
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
- src.mCompatInsetTypes,
+ src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -310,11 +309,11 @@ public final class WindowInsets {
@NonNull
public Insets getSystemWindowInsets() {
Insets result = mCompatIgnoreVisibility
- ? getInsetsIgnoringVisibility(mCompatInsetTypes & ~ime())
- : getInsets(mCompatInsetTypes);
+ ? getInsetsIgnoringVisibility(mCompatInsetsTypes & ~ime())
+ : getInsets(mCompatInsetsTypes);
// We can't query max insets for IME, so we need to add it manually after.
- if ((mCompatInsetTypes & ime()) != 0 && mCompatIgnoreVisibility) {
+ if ((mCompatInsetsTypes & ime()) != 0 && mCompatIgnoreVisibility) {
result = Insets.max(result, getInsets(ime()));
}
return result;
@@ -503,7 +502,7 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
null /* displayCutout */,
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -554,7 +553,7 @@ public final class WindowInsets {
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
displayCutoutCopyConstructorArgument(this),
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
// TODO(b/119190588): replace @code with @link below
@@ -627,7 +626,7 @@ public final class WindowInsets {
@Deprecated
@NonNull
public Insets getStableInsets() {
- return getInsets(mTypeMaxInsetsMap, mCompatInsetTypes);
+ return getInsets(mTypeMaxInsetsMap, mCompatInsetsTypes);
}
/**
@@ -939,7 +938,7 @@ public final class WindowInsets {
: mDisplayCutout == null
? DisplayCutout.NO_CUTOUT
: mDisplayCutout.inset(left, top, right, bottom),
- mCompatInsetTypes, mCompatIgnoreVisibility);
+ mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@Override
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 795e8f304f71..1d54d9251abb 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1229,32 +1229,54 @@ public interface WindowManager extends ViewManager {
* @hide
*/
@IntDef(prefix = "TYPE_", value = {
- TYPE_ACCESSIBILITY_OVERLAY,
+ TYPE_BASE_APPLICATION,
TYPE_APPLICATION,
- TYPE_APPLICATION_ATTACHED_DIALOG,
- TYPE_APPLICATION_MEDIA,
- TYPE_APPLICATION_OVERLAY,
- TYPE_APPLICATION_PANEL,
TYPE_APPLICATION_STARTING,
- TYPE_APPLICATION_SUB_PANEL,
- TYPE_BASE_APPLICATION,
TYPE_DRAWN_APPLICATION,
- TYPE_INPUT_METHOD,
- TYPE_INPUT_METHOD_DIALOG,
- TYPE_KEYGUARD,
- TYPE_KEYGUARD_DIALOG,
- TYPE_PHONE,
- TYPE_PRIORITY_PHONE,
- TYPE_PRIVATE_PRESENTATION,
- TYPE_SEARCH_BAR,
+ TYPE_APPLICATION_PANEL,
+ TYPE_APPLICATION_MEDIA,
+ TYPE_APPLICATION_SUB_PANEL,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ TYPE_APPLICATION_MEDIA_OVERLAY,
+ TYPE_APPLICATION_ABOVE_SUB_PANEL,
TYPE_STATUS_BAR,
- TYPE_STATUS_BAR_PANEL,
+ TYPE_SEARCH_BAR,
+ TYPE_PHONE,
TYPE_SYSTEM_ALERT,
+ TYPE_KEYGUARD,
+ TYPE_TOAST,
+ TYPE_SYSTEM_OVERLAY,
+ TYPE_PRIORITY_PHONE,
TYPE_SYSTEM_DIALOG,
+ TYPE_KEYGUARD_DIALOG,
TYPE_SYSTEM_ERROR,
- TYPE_SYSTEM_OVERLAY,
- TYPE_TOAST,
+ TYPE_INPUT_METHOD,
+ TYPE_INPUT_METHOD_DIALOG,
TYPE_WALLPAPER,
+ TYPE_STATUS_BAR_PANEL,
+ TYPE_SECURE_SYSTEM_OVERLAY,
+ TYPE_DRAG,
+ TYPE_STATUS_BAR_SUB_PANEL,
+ TYPE_POINTER,
+ TYPE_NAVIGATION_BAR,
+ TYPE_VOLUME_OVERLAY,
+ TYPE_BOOT_PROGRESS,
+ TYPE_INPUT_CONSUMER,
+ TYPE_NAVIGATION_BAR_PANEL,
+ TYPE_DISPLAY_OVERLAY,
+ TYPE_MAGNIFICATION_OVERLAY,
+ TYPE_PRIVATE_PRESENTATION,
+ TYPE_VOICE_INTERACTION,
+ TYPE_ACCESSIBILITY_OVERLAY,
+ TYPE_VOICE_INTERACTION_STARTING,
+ TYPE_DOCK_DIVIDER,
+ TYPE_QS_DIALOG,
+ TYPE_SCREENSHOT,
+ TYPE_PRESENTATION,
+ TYPE_APPLICATION_OVERLAY,
+ TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY,
+ TYPE_NOTIFICATION_SHADE,
+ TYPE_STATUS_BAR_ADDITIONAL
})
@Retention(RetentionPolicy.SOURCE)
public @interface WindowType {}
@@ -1715,6 +1737,46 @@ public interface WindowManager extends ViewManager {
public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "FLAG_", value = {
+ FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
+ FLAG_DIM_BEHIND,
+ FLAG_BLUR_BEHIND,
+ FLAG_NOT_FOCUSABLE,
+ FLAG_NOT_TOUCHABLE,
+ FLAG_NOT_TOUCH_MODAL,
+ FLAG_TOUCHABLE_WHEN_WAKING,
+ FLAG_KEEP_SCREEN_ON,
+ FLAG_LAYOUT_IN_SCREEN,
+ FLAG_LAYOUT_NO_LIMITS,
+ FLAG_FULLSCREEN,
+ FLAG_FORCE_NOT_FULLSCREEN,
+ FLAG_DITHER,
+ FLAG_SECURE,
+ FLAG_SCALED,
+ FLAG_IGNORE_CHEEK_PRESSES,
+ FLAG_LAYOUT_INSET_DECOR,
+ FLAG_ALT_FOCUSABLE_IM,
+ FLAG_WATCH_OUTSIDE_TOUCH,
+ FLAG_SHOW_WHEN_LOCKED,
+ FLAG_SHOW_WALLPAPER,
+ FLAG_TURN_SCREEN_ON,
+ FLAG_DISMISS_KEYGUARD,
+ FLAG_SPLIT_TOUCH,
+ FLAG_HARDWARE_ACCELERATED,
+ FLAG_LAYOUT_IN_OVERSCAN,
+ FLAG_TRANSLUCENT_STATUS,
+ FLAG_TRANSLUCENT_NAVIGATION,
+ FLAG_LOCAL_FOCUS_MODE,
+ FLAG_SLIPPERY,
+ FLAG_LAYOUT_ATTACHED_IN_DECOR,
+ FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Flags {}
+
+ /**
* Various behavioral options/flags. Default is none.
*
* @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
@@ -1809,6 +1871,7 @@ public interface WindowManager extends ViewManager {
@ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
name = "DRAWS_SYSTEM_BAR_BACKGROUNDS")
}, formatToHexString = true)
+ @Flags
public int flags;
/**
@@ -2027,6 +2090,7 @@ public interface WindowManager extends ViewManager {
* @hide
*/
public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000;
+
/**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*
@@ -2041,6 +2105,38 @@ public interface WindowManager extends ViewManager {
public @interface SystemFlags {}
/**
+ * @hide
+ */
+ @IntDef(flag = true, prefix="PRIVATE_FLAG_", value = {
+ PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
+ PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,
+ PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS,
+ SYSTEM_FLAG_SHOW_FOR_ALL_USERS,
+ PRIVATE_FLAG_NO_MOVE_ANIMATION,
+ PRIVATE_FLAG_COMPATIBLE_WINDOW,
+ PRIVATE_FLAG_SYSTEM_ERROR,
+ PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS,
+ PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR,
+ PRIVATE_FLAG_PRESERVE_GEOMETRY,
+ PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY,
+ PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH,
+ PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME,
+ PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS,
+ PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE,
+ SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY,
+ PRIVATE_FLAG_IS_SCREEN_DECOR,
+ PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION,
+ PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
+ PRIVATE_FLAG_USE_BLAST,
+ PRIVATE_FLAG_APPEARANCE_CONTROLLED,
+ PRIVATE_FLAG_BEHAVIOR_CONTROLLED,
+ PRIVATE_FLAG_FIT_INSETS_CONTROLLED,
+ PRIVATE_FLAG_TRUSTED_OVERLAY,
+ })
+ public @interface PrivateFlags {}
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -2127,6 +2223,10 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC,
name = "COLOR_SPACE_AGNOSTIC"),
@ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_USE_BLAST,
+ equals = PRIVATE_FLAG_USE_BLAST,
+ name = "USE_BLAST"),
+ @ViewDebug.FlagToString(
mask = PRIVATE_FLAG_APPEARANCE_CONTROLLED,
equals = PRIVATE_FLAG_APPEARANCE_CONTROLLED,
name = "APPEARANCE_CONTROLLED"),
@@ -2143,6 +2243,7 @@ public interface WindowManager extends ViewManager {
equals = PRIVATE_FLAG_TRUSTED_OVERLAY,
name = "TRUSTED_OVERLAY")
})
+ @PrivateFlags
@TestApi
public int privateFlags;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 28a18da37b3e..2fe7c021bb21 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -276,7 +276,7 @@ public final class WindowManagerImpl implements WindowManager {
if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
isScreenRound, alwaysConsumeSystemBars, displayCutout.get(),
- SOFT_INPUT_ADJUST_NOTHING,
+ SOFT_INPUT_ADJUST_NOTHING, attrs.flags,
SYSTEM_UI_FLAG_VISIBLE, null /* typeSideMap */);
} else {
return new WindowInsets.Builder()
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 492ab6f8a3d5..8c355202b63f 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -49,6 +49,13 @@ public interface WindowManagerPolicyConstants {
int PRESENCE_INTERNAL = 1 << 0;
int PRESENCE_EXTERNAL = 1 << 1;
+ // Alternate bars position values
+ int ALT_BAR_UNKNOWN = -1;
+ int ALT_BAR_LEFT = 1 << 0;
+ int ALT_BAR_RIGHT = 1 << 1;
+ int ALT_BAR_BOTTOM = 1 << 2;
+ int ALT_BAR_TOP = 1 << 3;
+
// Navigation bar position values
int NAV_BAR_INVALID = -1;
int NAV_BAR_LEFT = 1 << 0;
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 3f5ef5a2651d..64c59e54e85b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -43,8 +43,7 @@ import java.security.SecureRandom;
import java.util.ArrayList;
/**
- * Session used when the Android a system-provided content capture service
- * about events associated with views.
+ * Session used when notifying the Android system about events associated with views.
*/
public abstract class ContentCaptureSession implements AutoCloseable {
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 5820f4bdafad..135ff9fcd989 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -183,14 +183,14 @@ public abstract class CompoundButton extends Button implements Checkable {
public void setStateDescription(@Nullable CharSequence stateDescription) {
mCustomStateDescription = stateDescription;
if (stateDescription == null) {
- setDefaultStateDescritption();
+ setDefaultStateDescription();
} else {
super.setStateDescription(stateDescription);
}
}
/** @hide **/
- protected void setDefaultStateDescritption() {
+ protected void setDefaultStateDescription() {
if (mCustomStateDescription == null) {
super.setStateDescription(getButtonStateDescription());
}
@@ -210,6 +210,8 @@ public abstract class CompoundButton extends Button implements Checkable {
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
+ // setStateDescription will not send out event if the description is unchanged.
+ setDefaultStateDescription();
return;
}
@@ -228,7 +230,7 @@ public abstract class CompoundButton extends Button implements Checkable {
mBroadcasting = false;
}
// setStateDescription will not send out event if the description is unchanged.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
}
/**
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 4b32e10d083b..35605c4c6f6e 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -69,6 +69,7 @@ import com.android.internal.R;
import java.text.NumberFormat;
import java.util.ArrayList;
+import java.util.Locale;
/**
* <p>
@@ -249,6 +250,9 @@ public class ProgressBar extends View {
private ObjectAnimator mLastProgressAnimator;
+ private NumberFormat mPercentFormat;
+ private Locale mCachedLocale;
+
/**
* Create a new progress bar with range 0...100 and initial progress of 0.
* @param context the application environment
@@ -1591,8 +1595,15 @@ public class ProgressBar extends View {
* @return state description based on progress
*/
private CharSequence formatStateDescription(int progress) {
- return NumberFormat.getPercentInstance(mContext.getResources().getConfiguration().locale)
- .format(getPercent(progress));
+ // Cache the locale-appropriate NumberFormat. Configuration locale is guaranteed
+ // non-null, so the first time this is called we will always get the appropriate
+ // NumberFormat, then never regenerate it unless the locale changes on the fly.
+ final Locale curLocale = mContext.getResources().getConfiguration().getLocales().get(0);
+ if (!curLocale.equals(mCachedLocale)) {
+ mCachedLocale = curLocale;
+ mPercentFormat = NumberFormat.getPercentInstance(curLocale);
+ }
+ return mPercentFormat.format(getPercent(progress));
}
/**
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index e1fd77624a29..5bca56f14add 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -311,7 +311,7 @@ public class Switch extends CompoundButton {
refreshDrawableState();
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
setChecked(isChecked());
}
@@ -856,7 +856,7 @@ public class Switch extends CompoundButton {
requestLayout();
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
}
/**
@@ -879,7 +879,7 @@ public class Switch extends CompoundButton {
requestLayout();
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
}
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index eaa4c573b0e4..6f14dfb89e6b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11003,17 +11003,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* not among the handles.
*/
boolean isFromPrimePointer(MotionEvent event, boolean fromHandleView) {
+ boolean res = true;
if (mPrimePointerId == NO_POINTER_ID) {
mPrimePointerId = event.getPointerId(0);
mIsPrimePointerFromHandleView = fromHandleView;
} else if (mPrimePointerId != event.getPointerId(0)) {
- return mIsPrimePointerFromHandleView && fromHandleView;
+ res = mIsPrimePointerFromHandleView && fromHandleView;
}
if (event.getActionMasked() == MotionEvent.ACTION_UP
|| event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
mPrimePointerId = -1;
}
- return true;
+ return res;
}
@Override
diff --git a/core/java/android/widget/ToggleButton.java b/core/java/android/widget/ToggleButton.java
index 59e0c16cde37..24061a2ab05b 100644
--- a/core/java/android/widget/ToggleButton.java
+++ b/core/java/android/widget/ToggleButton.java
@@ -60,7 +60,7 @@ public class ToggleButton extends CompoundButton {
syncTextState();
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
a.recycle();
}
@@ -111,7 +111,7 @@ public class ToggleButton extends CompoundButton {
mTextOn = textOn;
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
}
/**
@@ -133,7 +133,7 @@ public class ToggleButton extends CompoundButton {
mTextOff = textOff;
// Default state is derived from on/off-text, so state has to be updated when on/off-text
// are updated.
- setDefaultStateDescritption();
+ setDefaultStateDescription();
}
/**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 233231cfcfdf..c3b570331671 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1202,7 +1202,7 @@ public class ResolverActivity extends Activity implements
final PackageManager pm = getPackageManager();
// Set the preferred Activity
- pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent());
+ pm.addUniquePreferredActivity(filter, bestMatch, set, intent.getComponent());
if (ri.handleAllWebDataURI) {
// Set default Browser if needed
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 8ea5aa815a1c..b4727499d8ef 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -21,6 +21,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.net.Ikev2VpnProfile;
import android.net.PlatformVpnProfile;
import android.net.ProxyInfo;
+import android.net.Uri;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -287,7 +288,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
profile.proxy = new ProxyInfo(host, port.isEmpty() ?
0 : Integer.parseInt(port), exclList);
} else if (!pacFileUrl.isEmpty()) {
- profile.proxy = new ProxyInfo(pacFileUrl);
+ profile.proxy = new ProxyInfo(Uri.parse(pacFileUrl));
}
} // else profile.proxy = null
diff --git a/core/java/com/android/internal/os/IDropBoxManagerService.aidl b/core/java/com/android/internal/os/IDropBoxManagerService.aidl
index 5e60394e5675..9141719d7a35 100644
--- a/core/java/com/android/internal/os/IDropBoxManagerService.aidl
+++ b/core/java/com/android/internal/os/IDropBoxManagerService.aidl
@@ -37,6 +37,10 @@ interface IDropBoxManagerService {
boolean isTagEnabled(String tag);
/** @see DropBoxManager#getNextEntry */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk=30,
+ publicAlternatives="Use {@link android.os.DropBoxManager#getNextEntry} instead")
DropBoxManager.Entry getNextEntry(String tag, long millis, String packageName);
+
+ DropBoxManager.Entry getNextEntryWithAttribution(String tag, long millis, String packageName,
+ String attributionTag);
}
diff --git a/core/java/com/android/internal/os/KernelWakelockReader.java b/core/java/com/android/internal/os/KernelWakelockReader.java
index cffb0ad9fdb9..3d35d2fbaa82 100644
--- a/core/java/com/android/internal/os/KernelWakelockReader.java
+++ b/core/java/com/android/internal/os/KernelWakelockReader.java
@@ -153,19 +153,32 @@ public class KernelWakelockReader {
}
/**
+ * Attempt to wait for suspend_control service if not immediately available.
+ */
+ private ISuspendControlService waitForSuspendControlService() throws ServiceNotFoundException {
+ final String name = "suspend_control";
+ final int numRetries = 5;
+ for (int i = 0; i < numRetries; i++) {
+ mSuspendControlService = ISuspendControlService.Stub.asInterface(
+ ServiceManager.getService(name));
+ if (mSuspendControlService != null) {
+ return mSuspendControlService;
+ }
+ }
+ throw new ServiceNotFoundException(name);
+ }
+
+ /**
* On success, returns the updated stats from SystemSupend, else returns null.
*/
private KernelWakelockStats getWakelockStatsFromSystemSuspend(
final KernelWakelockStats staleStats) {
WakeLockInfo[] wlStats = null;
- if (mSuspendControlService == null) {
- try {
- mSuspendControlService = ISuspendControlService.Stub.asInterface(
- ServiceManager.getServiceOrThrow("suspend_control"));
- } catch (ServiceNotFoundException e) {
- Slog.wtf(TAG, "Required service suspend_control not available", e);
- return null;
- }
+ try {
+ mSuspendControlService = waitForSuspendControlService();
+ } catch (ServiceNotFoundException e) {
+ Slog.wtf(TAG, "Required service suspend_control not available", e);
+ return null;
}
try {
diff --git a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
index 03948a92bcab..6c97962ac057 100644
--- a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
+++ b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
@@ -22,41 +22,54 @@ import android.view.inputmethod.InlineSuggestionsRequest;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
/**
- * Binder interface for the IME service to send an inline suggestion request to the system.
+ * Binder interface for the IME service to send {@link InlineSuggestionsRequest} or notify other IME
+ * service events to the system.
* {@hide}
*/
oneway interface IInlineSuggestionsRequestCallback {
- // Indicates that the current IME does not support inline suggestion.
+ /** Indicates that the current IME does not support inline suggestion. */
void onInlineSuggestionsUnsupported();
- // Sends the inline suggestions request from IME to Autofill. Calling this method indicates
- // that the IME input is started on the view corresponding to the request.
+ /**
+ * Sends the inline suggestions request from IME to Autofill. Calling this method indicates
+ * that the IME input is started on the view corresponding to the request.
+ */
void onInlineSuggestionsRequest(in InlineSuggestionsRequest request,
in IInlineSuggestionsResponseCallback callback);
- // Signals that {@link android.inputmethodservice.InputMethodService
- // #onStartInput(EditorInfo, boolean)} is called on the given focused field.
+ /**
+ * Signals that {@link android.inputmethodservice.InputMethodService
+ * #onStartInput(EditorInfo, boolean)} is called on the given focused field.
+ */
void onInputMethodStartInput(in AutofillId imeFieldId);
- // Signals that {@link android.inputmethodservice.InputMethodService
- // #dispatchOnShowInputRequested(int, boolean)} is called and shares the call result.
- // The true value of {@code requestResult} means the IME is about to be shown, while
- // false value means the IME will not be shown.
+ /**
+ * Signals that {@link android.inputmethodservice.InputMethodService
+ * #dispatchOnShowInputRequested(int, boolean)} is called and shares the call result.
+ * The true value of {@code requestResult} means the IME is about to be shown, while
+ * false value means the IME will not be shown.
+ */
void onInputMethodShowInputRequested(boolean requestResult);
- // Signals that {@link android.inputmethodservice.InputMethodService
- // #onStartInputView(EditorInfo, boolean)} is called on the field specified by the earlier
- // {@link #onInputMethodStartInput(AutofillId)}.
+ /**
+ * Signals that {@link android.inputmethodservice.InputMethodService
+ * #onStartInputView(EditorInfo, boolean)} is called on the field specified by the earlier
+ * {@link #onInputMethodStartInput(AutofillId)}.
+ */
void onInputMethodStartInputView();
- // Signals that {@link android.inputmethodservice.InputMethodService
- // #onFinishInputView(boolean)} is called on the field specified by the earlier
- // {@link #onInputMethodStartInput(AutofillId)}.
+ /**
+ * Signals that {@link android.inputmethodservice.InputMethodService
+ * #onFinishInputView(boolean)} is called on the field specified by the earlier
+ * {@link #onInputMethodStartInput(AutofillId)}.
+ */
void onInputMethodFinishInputView();
- // Signals that {@link android.inputmethodservice.InputMethodService
- // #onFinishInput()} is called on the field specified by the earlier
- // {@link #onInputMethodStartInput(AutofillId)}.
+ /**
+ * Signals that {@link android.inputmethodservice.InputMethodService
+ * #onFinishInput()} is called on the field specified by the earlier
+ * {@link #onInputMethodStartInput(AutofillId)}.
+ */
void onInputMethodFinishInput();
// Indicates that the current IME changes inline suggestion session.
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 9e2e85a7d041..b4b58ff903db 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -155,9 +155,8 @@ cc_library_shared {
"android_media_ToneGenerator.cpp",
"android_hardware_Camera.cpp",
"android_hardware_camera2_CameraMetadata.cpp",
- "android_hardware_camera2_legacy_LegacyCameraDevice.cpp",
- "android_hardware_camera2_legacy_PerfMeasurement.cpp",
"android_hardware_camera2_DngCreator.cpp",
+ "android_hardware_camera2_utils_SurfaceUtils.cpp",
"android_hardware_display_DisplayManagerGlobal.cpp",
"android_hardware_display_DisplayViewport.cpp",
"android_hardware_HardwareBuffer.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7b708efdb278..5b1196dd0f62 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -73,9 +73,8 @@ extern int register_android_opengl_jni_GLES32(JNIEnv* env);
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
-extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env);
-extern int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv *env);
extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
+extern int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env);
extern int register_android_hardware_display_DisplayManagerGlobal(JNIEnv* env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
@@ -1526,9 +1525,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
- REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice),
- REG_JNI(register_android_hardware_camera2_legacy_PerfMeasurement),
REG_JNI(register_android_hardware_camera2_DngCreator),
+ REG_JNI(register_android_hardware_camera2_utils_SurfaceUtils),
REG_JNI(register_android_hardware_display_DisplayManagerGlobal),
REG_JNI(register_android_hardware_HardwareBuffer),
REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index bc69735d7453..e47f18a943d9 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -556,7 +556,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz,
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
+ jobject weak_this, jint cameraId, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
@@ -566,19 +566,8 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
env->ReleaseStringChars(clientPackageName,
reinterpret_cast<const jchar*>(rawClientName));
- sp<Camera> camera;
- if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
- // Default path: hal version is don't care, do normal camera connect.
- camera = Camera::connect(cameraId, clientName,
- Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
- } else {
- jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
- Camera::USE_CALLING_UID, camera);
- if (status != NO_ERROR) {
- return status;
- }
- }
-
+ sp<Camera> camera =
+ Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
if (camera == NULL) {
return -EACCES;
}
@@ -1068,7 +1057,7 @@ static const JNINativeMethod camMethods[] = {
"(ILandroid/hardware/Camera$CameraInfo;)V",
(void*)android_hardware_Camera_getCameraInfo },
{ "native_setup",
- "(Ljava/lang/Object;IILjava/lang/String;)I",
+ "(Ljava/lang/Object;ILjava/lang/String;)I",
(void*)android_hardware_Camera_native_setup },
{ "native_release",
"()V",
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
deleted file mode 100644
index 8cf1d2cbfaae..000000000000
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ /dev/null
@@ -1,841 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Legacy-CameraDevice-JNI"
-// #define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Trace.h>
-#include <camera/CameraUtils.h>
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-#include "android_runtime/android_view_Surface.h"
-#include "android_runtime/android_graphics_SurfaceTexture.h"
-
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/IProducerListener.h>
-#include <gui/Surface.h>
-#include <hardware/camera3.h>
-#include <surfacetexture/SurfaceTexture.h>
-#include <system/camera_metadata.h>
-#include <system/window.h>
-#include <ui/GraphicBuffer.h>
-
-#include <stdint.h>
-#include <inttypes.h>
-
-using namespace android;
-
-// fully-qualified class name
-#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice"
-#define CAMERA_DEVICE_BUFFER_SLACK 3
-#define DONT_CARE 0
-
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
-
-#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
-
-// Use BAD_VALUE for surface abandoned error
-#define OVERRIDE_SURFACE_ERROR(err) \
-do { \
- if (err == -ENODEV) { \
- err = BAD_VALUE; \
- } \
-} while (0)
-
-#define UPDATE(md, tag, data, size) \
-do { \
- if ((md).update((tag), (data), (size))) { \
- ALOGE("Update " #tag " failed!"); \
- return BAD_VALUE; \
- } \
-} while (0)
-
-/**
- * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
- */
-static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
- uint8_t* crPlane, uint8_t* cbPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
- uint8_t R, G, B;
- size_t index = 0;
- for (size_t j = 0; j < height; j++) {
- uint8_t* cr = crPlane;
- uint8_t* cb = cbPlane;
- uint8_t* y = yPlane;
- bool jEven = (j & 1) == 0;
- for (size_t i = 0; i < width; i++) {
- R = rgbBuf[index++];
- G = rgbBuf[index++];
- B = rgbBuf[index++];
- *y++ = (77 * R + 150 * G + 29 * B) >> 8;
- if (jEven && (i & 1) == 0) {
- *cb = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
- *cr = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
- cr += chromaStep;
- cb += chromaStep;
- }
- // Skip alpha
- index++;
- }
- yPlane += yStride;
- if (jEven) {
- crPlane += chromaStride;
- cbPlane += chromaStride;
- }
- }
-}
-
-static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, android_ycbcr* ycbcr) {
- size_t cStep = ycbcr->chroma_step;
- size_t cStride = ycbcr->cstride;
- size_t yStride = ycbcr->ystride;
- ALOGV("%s: yStride is: %zu, cStride is: %zu, cStep is: %zu", __FUNCTION__, yStride, cStride,
- cStep);
- rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y),
- reinterpret_cast<uint8_t*>(ycbcr->cr), reinterpret_cast<uint8_t*>(ycbcr->cb),
- cStep, yStride, cStride);
-}
-
-static status_t connectSurface(const sp<Surface>& surface, int32_t maxBufferSlack) {
- status_t err = NO_ERROR;
-
- err = surface->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/NULL);
- if (err != OK) {
- ALOGE("%s: Unable to connect to surface, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
-
- err = native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- int minUndequeuedBuffers;
- err = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
- __FUNCTION__, strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- ALOGV("%s: Setting buffer count to %d", __FUNCTION__,
- maxBufferSlack + 1 + minUndequeuedBuffers);
- err = native_window_set_buffer_count(surface.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-/**
- * Produce a frame in the given surface.
- *
- * Args:
- * anw - a surface to produce a frame in.
- * pixelBuffer - image buffer to generate a frame from.
- * width - width of the pixelBuffer in pixels.
- * height - height of the pixelBuffer in pixels.
- * pixelFmt - format of the pixelBuffer, one of:
- * HAL_PIXEL_FORMAT_YCrCb_420_SP,
- * HAL_PIXEL_FORMAT_YCbCr_420_888,
- * HAL_PIXEL_FORMAT_BLOB
- * bufSize - the size of the pixelBuffer in bytes.
- */
-static status_t produceFrame(const sp<ANativeWindow>& anw,
- uint8_t* pixelBuffer,
- int32_t bufWidth, // Width of the pixelBuffer
- int32_t bufHeight, // Height of the pixelBuffer
- int32_t pixelFmt, // Format of the pixelBuffer
- int32_t bufSize) {
- ATRACE_CALL();
- status_t err = NO_ERROR;
- ANativeWindowBuffer* anb;
- ALOGV("%s: Dequeue buffer from %p %dx%d (fmt=%x, size=%x)",
- __FUNCTION__, anw.get(), bufWidth, bufHeight, pixelFmt, bufSize);
-
- if (anw == 0) {
- ALOGE("%s: anw must not be NULL", __FUNCTION__);
- return BAD_VALUE;
- } else if (pixelBuffer == NULL) {
- ALOGE("%s: pixelBuffer must not be NULL", __FUNCTION__);
- return BAD_VALUE;
- } else if (bufWidth < 0) {
- ALOGE("%s: width must be non-negative", __FUNCTION__);
- return BAD_VALUE;
- } else if (bufHeight < 0) {
- ALOGE("%s: height must be non-negative", __FUNCTION__);
- return BAD_VALUE;
- } else if (bufSize < 0) {
- ALOGE("%s: bufSize must be non-negative", __FUNCTION__);
- return BAD_VALUE;
- }
-
- size_t width = static_cast<size_t>(bufWidth);
- size_t height = static_cast<size_t>(bufHeight);
- size_t bufferLength = static_cast<size_t>(bufSize);
-
- // TODO: Switch to using Surface::lock and Surface::unlockAndPost
- err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to dequeue buffer, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
- uint32_t grallocBufWidth = buf->getWidth();
- uint32_t grallocBufHeight = buf->getHeight();
- uint32_t grallocBufStride = buf->getStride();
- if (grallocBufWidth != width || grallocBufHeight != height) {
- ALOGE("%s: Received gralloc buffer with bad dimensions %" PRIu32 "x%" PRIu32
- ", expecting dimensions %zu x %zu", __FUNCTION__, grallocBufWidth,
- grallocBufHeight, width, height);
- return BAD_VALUE;
- }
-
- int32_t bufFmt = 0;
- err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &bufFmt);
- if (err != NO_ERROR) {
- ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- uint64_t tmpSize = (pixelFmt == HAL_PIXEL_FORMAT_BLOB) ? grallocBufWidth :
- 4 * grallocBufHeight * grallocBufWidth;
- if (bufFmt != pixelFmt) {
- if (bufFmt == HAL_PIXEL_FORMAT_RGBA_8888 && pixelFmt == HAL_PIXEL_FORMAT_BLOB) {
- ALOGV("%s: Using BLOB to RGBA format override.", __FUNCTION__);
- tmpSize = 4 * (grallocBufWidth + grallocBufStride * (grallocBufHeight - 1));
- } else {
- ALOGW("%s: Format mismatch in produceFrame: expecting format %#" PRIx32
- ", but received buffer with format %#" PRIx32, __FUNCTION__, pixelFmt, bufFmt);
- }
- }
-
- if (tmpSize > SIZE_MAX) {
- ALOGE("%s: Overflow calculating size, buffer with dimens %zu x %zu is absurdly large...",
- __FUNCTION__, width, height);
- return BAD_VALUE;
- }
-
- size_t totalSizeBytes = tmpSize;
-
- ALOGV("%s: Pixel format chosen: %x", __FUNCTION__, pixelFmt);
- switch(pixelFmt) {
- case HAL_PIXEL_FORMAT_YCrCb_420_SP: {
- if (bufferLength < totalSizeBytes) {
- ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
- __FUNCTION__, bufferLength);
- return BAD_VALUE;
- }
- uint8_t* img = NULL;
- ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) return err;
-
- uint8_t* yPlane = img;
- uint8_t* uPlane = img + height * width;
- uint8_t* vPlane = uPlane + 1;
- size_t chromaStep = 2;
- size_t yStride = width;
- size_t chromaStride = width;
-
- rgbToYuv420(pixelBuffer, width, height, yPlane,
- uPlane, vPlane, chromaStep, yStride, chromaStride);
- break;
- }
- case HAL_PIXEL_FORMAT_YV12: {
- if (bufferLength < totalSizeBytes) {
- ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
- __FUNCTION__, bufferLength);
- return BAD_VALUE;
- }
-
- if ((width & 1) || (height & 1)) {
- ALOGE("%s: Dimens %zu x %zu are not divisible by 2.", __FUNCTION__, width, height);
- return BAD_VALUE;
- }
-
- uint8_t* img = NULL;
- ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
-
- uint32_t stride = buf->getStride();
- ALOGV("%s: stride is: %" PRIu32, __FUNCTION__, stride);
- LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride);
-
- uint32_t cStride = ALIGN(stride / 2, 16);
- size_t chromaStep = 1;
-
- uint8_t* yPlane = img;
- uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride;
- uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2;
-
- rgbToYuv420(pixelBuffer, width, height, yPlane,
- crPlane, cbPlane, chromaStep, stride, cStride);
- break;
- }
- case HAL_PIXEL_FORMAT_YCbCr_420_888: {
- // Software writes with YCbCr_420_888 format are unsupported
- // by the gralloc module for now
- if (bufferLength < totalSizeBytes) {
- ALOGE("%s: PixelBuffer size %zu too small for given dimensions",
- __FUNCTION__, bufferLength);
- return BAD_VALUE;
- }
- android_ycbcr ycbcr = android_ycbcr();
- ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get());
-
- err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
- rgbToYuv420(pixelBuffer, width, height, &ycbcr);
- break;
- }
- case HAL_PIXEL_FORMAT_BLOB: {
- int8_t* img = NULL;
- struct camera3_jpeg_blob footer = {
- .jpeg_blob_id = CAMERA3_JPEG_BLOB_ID,
- .jpeg_size = (uint32_t)bufferLength
- };
-
- size_t totalJpegSize = bufferLength + sizeof(footer);
- totalJpegSize = (totalJpegSize + 3) & ~0x3; // round up to nearest octonibble
-
- if (totalJpegSize > totalSizeBytes) {
- ALOGE("%s: Pixel buffer needs size %zu, cannot fit in gralloc buffer of size %zu",
- __FUNCTION__, totalJpegSize, totalSizeBytes);
- return BAD_VALUE;
- }
-
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err),
- err);
- return err;
- }
-
- memcpy(img, pixelBuffer, bufferLength);
- memcpy(img + totalSizeBytes - sizeof(footer), &footer, sizeof(footer));
- break;
- }
- default: {
- ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt);
- return BAD_VALUE;
- }
- }
-
- ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get());
- err = buf->unlock();
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
- return err;
- }
-
- ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get());
- err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
- if (err != NO_ERROR) {
- ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
- sp<ANativeWindow> anw;
- if (surface) {
- anw = android_view_Surface_getNativeWindow(env, surface);
- if (env->ExceptionCheck()) {
- return NULL;
- }
- } else {
- jniThrowNullPointerException(env, "surface");
- return NULL;
- }
- if (anw == NULL) {
- ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
- return NULL;
- }
- return anw;
-}
-
-static sp<ANativeWindow> getSurfaceTextureNativeWindow(JNIEnv* env, jobject thiz) {
- sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
- sp<Surface> surfaceTextureClient(producer != NULL ? new Surface(producer) : NULL);
- return surfaceTextureClient;
-}
-
-static sp<ANativeWindow> getNativeWindowFromTexture(JNIEnv* env, jobject surfaceTexture) {
- sp<ANativeWindow> anw;
- if (surfaceTexture) {
- anw = getSurfaceTextureNativeWindow(env, surfaceTexture);
- if (env->ExceptionCheck()) {
- return NULL;
- }
- } else {
- jniThrowNullPointerException(env, "surfaceTexture");
- return NULL;
- }
- if (anw == NULL) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "SurfaceTexture had no valid native window.");
- return NULL;
- }
- return anw;
-}
-
-static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
- sp<Surface> s;
- if (surface) {
- s = android_view_Surface_getSurface(env, surface);
- if (env->ExceptionCheck()) {
- return NULL;
- }
- } else {
- jniThrowNullPointerException(env, "surface");
- return NULL;
- }
- if (s == NULL) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "Surface had no valid native Surface.");
- return NULL;
- }
- return s;
-}
-
-extern "C" {
-
-static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
- ALOGV("nativeDetectSurfaceType");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- int32_t fmt = 0;
- status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
- err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return fmt;
-}
-
-static jint LegacyCameraDevice_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
- ALOGV("nativeDetectSurfaceDataspace");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- int32_t fmt = 0;
- status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying surface dataspace %s (%d).", __FUNCTION__, strerror(-err),
- err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return fmt;
-}
-
-static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
- jobject surface, jintArray dimens) {
- ALOGV("nativeGetSurfaceDimens");
-
- if (dimens == NULL) {
- ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
- return BAD_VALUE;
- }
-
- if (env->GetArrayLength(dimens) < 2) {
- ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
- return BAD_VALUE;
- }
-
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- int32_t dimenBuf[2];
- status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
- err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
- err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
- jobject surface) {
- ALOGV("nativeDetectSurfaceUsageFlags");
-
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "Could not retrieve native window from surface.");
- return BAD_VALUE;
- }
- int32_t usage = 0;
- status_t err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &usage);
- if(err != NO_ERROR) {
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "Error while querying surface usage bits");
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return usage;
-}
-
-static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz,
- jobject surface) {
- ALOGV("nativeDisconnectSurface");
- if (surface == nullptr) return NO_ERROR;
-
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGV("Buffer queue has already been abandoned.");
- return NO_ERROR;
- }
-
- status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
- if(err != NO_ERROR) {
- jniThrowException(env, "java/lang/UnsupportedOperationException",
- "Error while disconnecting surface");
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
- jobject surfaceTexture, jintArray dimens) {
- ALOGV("nativeDetectTextureDimens");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindowFromTexture(env, surfaceTexture)) == NULL) {
- ALOGE("%s: Could not retrieve native window from SurfaceTexture.", __FUNCTION__);
- return BAD_VALUE;
- }
-
- int32_t dimenBuf[2];
- status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
- if(err != NO_ERROR) {
- ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
- strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
-
- env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
- if (env->ExceptionCheck()) {
- return BAD_VALUE;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeConnectSurface(JNIEnv* env, jobject thiz, jobject surface) {
- ALOGV("nativeConnectSurface");
- sp<Surface> s;
- if ((s = getSurface(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
- if (err != NO_ERROR) {
- ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface,
- jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) {
- ALOGV("nativeProduceFrame");
- sp<ANativeWindow> anw;
-
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
-
- if (pixelBuffer == NULL) {
- jniThrowNullPointerException(env, "pixelBuffer");
- return DONT_CARE;
- }
-
- int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer));
- jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL);
-
- if (pixels == NULL) {
- jniThrowNullPointerException(env, "pixels");
- return DONT_CARE;
- }
-
- status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height,
- pixelFormat, bufSize);
- env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT);
-
- if (err != NO_ERROR) {
- ALOGE("%s: Error while producing frame %s (%d).", __FUNCTION__, strerror(-err), err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface,
- jint pixelFormat) {
- ALOGV("nativeSetSurfaceType");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
- if (err != NO_ERROR) {
- ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
- jint width, jint height) {
- ALOGV("nativeSetSurfaceDimens");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
-
- // Set user dimensions only
- // The producer dimensions are owned by GL
- status_t err = native_window_set_buffers_user_dimensions(anw.get(), width, height);
- if (err != NO_ERROR) {
- ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
- err);
- OVERRIDE_SURFACE_ERROR(err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jlong LegacyCameraDevice_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
- ALOGV("nativeGetSurfaceId");
- sp<Surface> s;
- if ((s = getSurface(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
- return 0;
- }
- sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
- if (gbp == NULL) {
- ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
- return 0;
- }
- sp<IBinder> b = IInterface::asBinder(gbp);
- if (b == NULL) {
- ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
- return 0;
- }
- /*
- * FIXME: Use better unique ID for surfaces than native IBinder pointer. Fix also in the camera
- * service (CameraDeviceClient.h).
- */
- return reinterpret_cast<jlong>(b.get());
-}
-
-static jint LegacyCameraDevice_nativeSetSurfaceOrientation(JNIEnv* env, jobject thiz,
- jobject surface, jint facing, jint orientation) {
- ALOGV("nativeSetSurfaceOrientation");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
-
- status_t err = NO_ERROR;
- CameraMetadata staticMetadata;
-
- int32_t orientVal = static_cast<int32_t>(orientation);
- uint8_t facingVal = static_cast<uint8_t>(facing);
- staticMetadata.update(ANDROID_SENSOR_ORIENTATION, &orientVal, 1);
- staticMetadata.update(ANDROID_LENS_FACING, &facingVal, 1);
-
- int32_t transform = 0;
-
- if ((err = CameraUtils::getRotationTransform(staticMetadata, /*out*/&transform)) != NO_ERROR) {
- ALOGE("%s: Invalid rotation transform %s (%d)", __FUNCTION__, strerror(-err),
- err);
- return err;
- }
-
- ALOGV("%s: Setting buffer sticky transform to %d", __FUNCTION__, transform);
-
- if ((err = native_window_set_buffers_sticky_transform(anw.get(), transform)) != NO_ERROR) {
- ALOGE("%s: Unable to configure surface transform, error %s (%d)", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
-
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeSetNextTimestamp(JNIEnv* env, jobject thiz, jobject surface,
- jlong timestamp) {
- ALOGV("nativeSetNextTimestamp");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
-
- status_t err = NO_ERROR;
-
- if ((err = native_window_set_buffers_timestamp(anw.get(), static_cast<int64_t>(timestamp))) !=
- NO_ERROR) {
- ALOGE("%s: Unable to set surface timestamp, error %s (%d)", __FUNCTION__, strerror(-err),
- err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeSetScalingMode(JNIEnv* env, jobject thiz, jobject surface,
- jint mode) {
- ALOGV("nativeSetScalingMode");
- sp<ANativeWindow> anw;
- if ((anw = getNativeWindow(env, surface)) == NULL) {
- ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
- return BAD_VALUE;
- }
- status_t err = NO_ERROR;
- if ((err = native_window_set_scaling_mode(anw.get(), static_cast<int>(mode))) != NO_ERROR) {
- ALOGE("%s: Unable to set surface scaling mode, error %s (%d)", __FUNCTION__,
- strerror(-err), err);
- return err;
- }
- return NO_ERROR;
-}
-
-static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
- ALOGV("nativeGetJpegFooterSize");
- return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
-}
-
-} // extern "C"
-
-static const JNINativeMethod gCameraDeviceMethods[] = {
- { "nativeDetectSurfaceType",
- "(Landroid/view/Surface;)I",
- (void *)LegacyCameraDevice_nativeDetectSurfaceType },
- { "nativeDetectSurfaceDataspace",
- "(Landroid/view/Surface;)I",
- (void *)LegacyCameraDevice_nativeDetectSurfaceDataspace },
- { "nativeDetectSurfaceDimens",
- "(Landroid/view/Surface;[I)I",
- (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
- { "nativeConnectSurface",
- "(Landroid/view/Surface;)I",
- (void *)LegacyCameraDevice_nativeConnectSurface },
- { "nativeProduceFrame",
- "(Landroid/view/Surface;[BIII)I",
- (void *)LegacyCameraDevice_nativeProduceFrame },
- { "nativeSetSurfaceFormat",
- "(Landroid/view/Surface;I)I",
- (void *)LegacyCameraDevice_nativeSetSurfaceFormat },
- { "nativeSetSurfaceDimens",
- "(Landroid/view/Surface;II)I",
- (void *)LegacyCameraDevice_nativeSetSurfaceDimens },
- { "nativeGetSurfaceId",
- "(Landroid/view/Surface;)J",
- (void *)LegacyCameraDevice_nativeGetSurfaceId },
- { "nativeDetectTextureDimens",
- "(Landroid/graphics/SurfaceTexture;[I)I",
- (void *)LegacyCameraDevice_nativeDetectTextureDimens },
- { "nativeSetSurfaceOrientation",
- "(Landroid/view/Surface;II)I",
- (void *)LegacyCameraDevice_nativeSetSurfaceOrientation },
- { "nativeSetNextTimestamp",
- "(Landroid/view/Surface;J)I",
- (void *)LegacyCameraDevice_nativeSetNextTimestamp },
- { "nativeGetJpegFooterSize",
- "()I",
- (void *)LegacyCameraDevice_nativeGetJpegFooterSize },
- { "nativeDetectSurfaceUsageFlags",
- "(Landroid/view/Surface;)I",
- (void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
- { "nativeSetScalingMode",
- "(Landroid/view/Surface;I)I",
- (void *)LegacyCameraDevice_nativeSetScalingMode },
- { "nativeDisconnectSurface",
- "(Landroid/view/Surface;)I",
- (void *)LegacyCameraDevice_nativeDisconnectSurface },
-};
-
-// Get all the required offsets in java class and register native functions
-int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env)
-{
- // Register native functions
- return RegisterMethodsOrDie(env,
- CAMERA_DEVICE_CLASS_NAME,
- gCameraDeviceMethods,
- NELEM(gCameraDeviceMethods));
-}
diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
deleted file mode 100644
index fac243a70415..000000000000
--- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Camera2-Legacy-PerfMeasurement-JNI"
-#include <utils/Log.h>
-#include <utils/Errors.h>
-#include <utils/Trace.h>
-#include <utils/Vector.h>
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
-#include <ui/GraphicBuffer.h>
-#include <system/window.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-using namespace android;
-
-// fully-qualified class name
-#define PERF_MEASUREMENT_CLASS_NAME "android/hardware/camera2/legacy/PerfMeasurement"
-
-/** GL utility methods copied from com_google_android_gles_jni_GLImpl.cpp */
-
-// Check if the extension at the head of pExtensions is pExtension. Note that pExtensions is
-// terminated by either 0 or space, while pExtension is terminated by 0.
-
-static bool
-extensionEqual(const GLubyte* pExtensions, const GLubyte* pExtension) {
- while (true) {
- char a = *pExtensions++;
- char b = *pExtension++;
- bool aEnd = a == '\0' || a == ' ';
- bool bEnd = b == '\0';
- if (aEnd || bEnd) {
- return aEnd == bEnd;
- }
- if (a != b) {
- return false;
- }
- }
-}
-
-static const GLubyte*
-nextExtension(const GLubyte* pExtensions) {
- while (true) {
- char a = *pExtensions++;
- if (a == '\0') {
- return pExtensions-1;
- } else if ( a == ' ') {
- return pExtensions;
- }
- }
-}
-
-static bool
-checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
- for (; *pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
- if (extensionEqual(pExtensions, pExtension)) {
- return true;
- }
- }
- return false;
-}
-
-/** End copied GL utility methods */
-
-bool checkGlError(JNIEnv* env) {
- int error;
- if ((error = glGetError()) != GL_NO_ERROR) {
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "GLES20 error: 0x%d", error);
- return true;
- }
- return false;
-}
-
-/**
- * Asynchronous low-overhead GL performance measurement using
- * http://www.khronos.org/registry/gles/extensions/EXT/EXT_disjoint_timer_query.txt
- *
- * Measures the duration of GPU processing for a set of GL commands, delivering
- * the measurement asynchronously once processing completes.
- *
- * All calls must come from a single thread with a valid GL context active.
- **/
-class PerfMeasurementContext {
- private:
- Vector<GLuint> mTimingQueries;
- size_t mTimingStartIndex;
- size_t mTimingEndIndex;
- size_t mTimingQueryIndex;
- size_t mFreeQueries;
-
- bool mInitDone;
- public:
-
- /**
- * maxQueryCount should be a conservative estimate of how many query objects
- * will be active at once, which is a function of the GPU's level of
- * pipelining and the frequency of queries.
- */
- explicit PerfMeasurementContext(size_t maxQueryCount):
- mTimingStartIndex(0),
- mTimingEndIndex(0),
- mTimingQueryIndex(0) {
- mTimingQueries.resize(maxQueryCount);
- mFreeQueries = maxQueryCount;
- mInitDone = false;
- }
-
- int getMaxQueryCount() {
- return mTimingQueries.size();
- }
-
- /**
- * Start a measurement period using the next available query object.
- * Returns INVALID_OPERATION if called multiple times in a row,
- * and BAD_VALUE if no more query objects are available.
- */
- int startGlTimer() {
- // Lazy init of queries to avoid needing GL context during construction
- if (!mInitDone) {
- glGenQueriesEXT(mTimingQueries.size(), mTimingQueries.editArray());
- mInitDone = true;
- }
-
- if (mTimingEndIndex != mTimingStartIndex) {
- return INVALID_OPERATION;
- }
-
- if (mFreeQueries == 0) {
- return BAD_VALUE;
- }
-
- glBeginQueryEXT(GL_TIME_ELAPSED_EXT, mTimingQueries[mTimingStartIndex]);
-
- mTimingStartIndex = (mTimingStartIndex + 1) % mTimingQueries.size();
- mFreeQueries--;
-
- return OK;
- }
-
- /**
- * Finish the current measurement period
- * Returns INVALID_OPERATION if called before any startGLTimer calls
- * or if called multiple times in a row.
- */
- int stopGlTimer() {
- size_t nextEndIndex = (mTimingEndIndex + 1) % mTimingQueries.size();
- if (nextEndIndex != mTimingStartIndex) {
- return INVALID_OPERATION;
- }
- glEndQueryEXT(GL_TIME_ELAPSED_EXT);
-
- mTimingEndIndex = nextEndIndex;
-
- return OK;
- }
-
- static const nsecs_t NO_DURATION_YET = -1L;
- static const nsecs_t FAILED_MEASUREMENT = -2L;
-
- /**
- * Get the next available duration measurement.
- *
- * Returns NO_DURATION_YET if no new measurement is available,
- * and FAILED_MEASUREMENT if an error occurred during the next
- * measurement period.
- *
- * Otherwise returns a positive number of nanoseconds measuring the
- * duration of the oldest completed query.
- */
- nsecs_t getNextGlDuration() {
- if (!mInitDone) {
- // No start/stop called yet
- return NO_DURATION_YET;
- }
-
- GLint available;
- glGetQueryObjectivEXT(mTimingQueries[mTimingQueryIndex],
- GL_QUERY_RESULT_AVAILABLE_EXT, &available);
- if (!available) {
- return NO_DURATION_YET;
- }
-
- GLint64 duration = FAILED_MEASUREMENT;
- GLint disjointOccurred;
- glGetIntegerv(GL_GPU_DISJOINT_EXT, &disjointOccurred);
-
- if (!disjointOccurred) {
- glGetQueryObjecti64vEXT(mTimingQueries[mTimingQueryIndex],
- GL_QUERY_RESULT_EXT,
- &duration);
- }
-
- mTimingQueryIndex = (mTimingQueryIndex + 1) % mTimingQueries.size();
- mFreeQueries++;
-
- return static_cast<nsecs_t>(duration);
- }
-
- static bool isMeasurementSupported() {
- const GLubyte* extensions = glGetString(GL_EXTENSIONS);
- return checkForExtension(extensions,
- reinterpret_cast<const GLubyte*>("GL_EXT_disjoint_timer_query"));
- }
-
-};
-
-PerfMeasurementContext* getContext(jlong context) {
- return reinterpret_cast<PerfMeasurementContext*>(context);
-}
-
-extern "C" {
-
-static jlong PerfMeasurement_nativeCreateContext(JNIEnv* env, jobject thiz,
- jint maxQueryCount) {
- PerfMeasurementContext *context = new PerfMeasurementContext(maxQueryCount);
- return reinterpret_cast<jlong>(context);
-}
-
-static void PerfMeasurement_nativeDeleteContext(JNIEnv* env, jobject thiz,
- jlong contextHandle) {
- PerfMeasurementContext *context = getContext(contextHandle);
- delete(context);
-}
-
-static jboolean PerfMeasurement_nativeQuerySupport(JNIEnv* env, jobject thiz) {
- bool supported = PerfMeasurementContext::isMeasurementSupported();
- checkGlError(env);
- return static_cast<jboolean>(supported);
-}
-
-static void PerfMeasurement_nativeStartGlTimer(JNIEnv* env, jobject thiz,
- jlong contextHandle) {
-
- PerfMeasurementContext *context = getContext(contextHandle);
- status_t err = context->startGlTimer();
- if (err != OK) {
- switch (err) {
- case INVALID_OPERATION:
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Mismatched start/end GL timing calls");
- return;
- case BAD_VALUE:
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Too many timing queries in progress, max %d",
- context->getMaxQueryCount());
- return;
- default:
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Unknown error starting GL timing");
- return;
- }
- }
- checkGlError(env);
-}
-
-static void PerfMeasurement_nativeStopGlTimer(JNIEnv* env, jobject thiz,
- jlong contextHandle) {
-
- PerfMeasurementContext *context = getContext(contextHandle);
- status_t err = context->stopGlTimer();
- if (err != OK) {
- switch (err) {
- case INVALID_OPERATION:
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Mismatched start/end GL timing calls");
- return;
- default:
- jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
- "Unknown error ending GL timing");
- return;
- }
- }
- checkGlError(env);
-}
-
-static jlong PerfMeasurement_nativeGetNextGlDuration(JNIEnv* env,
- jobject thiz, jlong contextHandle) {
- PerfMeasurementContext *context = getContext(contextHandle);
- nsecs_t duration = context->getNextGlDuration();
-
- checkGlError(env);
- return static_cast<jlong>(duration);
-}
-
-} // extern "C"
-
-static const JNINativeMethod gPerfMeasurementMethods[] = {
- { "nativeCreateContext",
- "(I)J",
- (jlong *)PerfMeasurement_nativeCreateContext },
- { "nativeDeleteContext",
- "(J)V",
- (void *)PerfMeasurement_nativeDeleteContext },
- { "nativeQuerySupport",
- "()Z",
- (jboolean *)PerfMeasurement_nativeQuerySupport },
- { "nativeStartGlTimer",
- "(J)V",
- (void *)PerfMeasurement_nativeStartGlTimer },
- { "nativeStopGlTimer",
- "(J)V",
- (void *)PerfMeasurement_nativeStopGlTimer },
- { "nativeGetNextGlDuration",
- "(J)J",
- (jlong *)PerfMeasurement_nativeGetNextGlDuration }
-};
-
-
-// Get all the required offsets in java class and register native functions
-int register_android_hardware_camera2_legacy_PerfMeasurement(JNIEnv* env)
-{
- // Register native functions
- return RegisterMethodsOrDie(env,
- PERF_MEASUREMENT_CLASS_NAME,
- gPerfMeasurementMethods,
- NELEM(gPerfMeasurementMethods));
-}
diff --git a/core/jni/android_hardware_camera2_utils_SurfaceUtils.cpp b/core/jni/android_hardware_camera2_utils_SurfaceUtils.cpp
new file mode 100644
index 000000000000..2437a511238c
--- /dev/null
+++ b/core/jni/android_hardware_camera2_utils_SurfaceUtils.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Camera-SurfaceUtils-JNI"
+// #define LOG_NDEBUG 0
+#include <camera/CameraUtils.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <nativehelper/JNIHelp.h>
+#include "android_runtime/android_graphics_SurfaceTexture.h"
+#include "android_runtime/android_view_Surface.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+#include <system/window.h>
+#include <ui/GraphicBuffer.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+
+using namespace android;
+
+// fully-qualified class name
+#define CAMERA_UTILS_CLASS_NAME "android/hardware/camera2/utils/SurfaceUtils"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
+#define OVERRIDE_SURFACE_ERROR(err) \
+ do { \
+ if (err == -ENODEV) { \
+ err = BAD_VALUE; \
+ } \
+ } while (0)
+
+static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
+ sp<ANativeWindow> anw;
+ if (surface) {
+ anw = android_view_Surface_getNativeWindow(env, surface);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ } else {
+ jniThrowNullPointerException(env, "surface");
+ return NULL;
+ }
+ if (anw == NULL) {
+ ALOGE("%s: Surface had no valid native window.", __FUNCTION__);
+ return NULL;
+ }
+ return anw;
+}
+
+static sp<Surface> getSurface(JNIEnv* env, jobject surface) {
+ sp<Surface> s;
+ if (surface) {
+ s = android_view_Surface_getSurface(env, surface);
+ if (env->ExceptionCheck()) {
+ return NULL;
+ }
+ } else {
+ jniThrowNullPointerException(env, "surface");
+ return NULL;
+ }
+ if (s == NULL) {
+ jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ "Surface had no valid native Surface.");
+ return NULL;
+ }
+ return s;
+}
+
+extern "C" {
+
+static jint SurfaceUtils_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) {
+ ALOGV("nativeDetectSurfaceType");
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ int32_t fmt = 0;
+ status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
+ strerror(-err), err);
+ OVERRIDE_SURFACE_ERROR(err);
+ return err;
+ }
+ return fmt;
+}
+
+static jint SurfaceUtils_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
+ ALOGV("nativeDetectSurfaceDataspace");
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ int32_t fmt = 0;
+ status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface dataspace %s (%d).", __FUNCTION__, strerror(-err),
+ err);
+ OVERRIDE_SURFACE_ERROR(err);
+ return err;
+ }
+ return fmt;
+}
+
+static jint SurfaceUtils_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface,
+ jintArray dimens) {
+ ALOGV("nativeGetSurfaceDimens");
+
+ if (dimens == NULL) {
+ ALOGE("%s: Null dimens argument passed to nativeDetectSurfaceDimens", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (env->GetArrayLength(dimens) < 2) {
+ ALOGE("%s: Invalid length of dimens argument in nativeDetectSurfaceDimens", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ int32_t dimenBuf[2];
+ status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err), err);
+ OVERRIDE_SURFACE_ERROR(err);
+ return err;
+ }
+ err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
+ if (err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
+ err);
+ OVERRIDE_SURFACE_ERROR(err);
+ return err;
+ }
+ env->SetIntArrayRegion(dimens, /*start*/ 0, /*length*/ ARRAY_SIZE(dimenBuf), dimenBuf);
+ return NO_ERROR;
+}
+
+static jlong SurfaceUtils_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobject thiz,
+ jobject surface) {
+ ALOGV("nativeDetectSurfaceUsageFlags");
+
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "Could not retrieve native window from surface.");
+ return BAD_VALUE;
+ }
+ uint64_t usage = 0;
+ status_t err = native_window_get_consumer_usage(anw.get(), &usage);
+ if (err != NO_ERROR) {
+ jniThrowException(env, "java/lang/UnsupportedOperationException",
+ "Error while querying surface usage bits");
+ OVERRIDE_SURFACE_ERROR(err);
+ return err;
+ }
+ return usage;
+}
+
+static jlong SurfaceUtils_nativeGetSurfaceId(JNIEnv* env, jobject thiz, jobject surface) {
+ ALOGV("nativeGetSurfaceId");
+ sp<Surface> s;
+ if ((s = getSurface(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native Surface from surface.", __FUNCTION__);
+ return 0;
+ }
+ sp<IGraphicBufferProducer> gbp = s->getIGraphicBufferProducer();
+ if (gbp == NULL) {
+ ALOGE("%s: Could not retrieve IGraphicBufferProducer from surface.", __FUNCTION__);
+ return 0;
+ }
+ sp<IBinder> b = IInterface::asBinder(gbp);
+ if (b == NULL) {
+ ALOGE("%s: Could not retrieve IBinder from surface.", __FUNCTION__);
+ return 0;
+ }
+ /*
+ * FIXME: Use better unique ID for surfaces than native IBinder pointer. Fix also in the camera
+ * service (CameraDeviceClient.h).
+ */
+ return reinterpret_cast<jlong>(b.get());
+}
+
+} // extern "C"
+
+static const JNINativeMethod gCameraSurfaceUtilsMethods[] = {
+ {"nativeDetectSurfaceType", "(Landroid/view/Surface;)I",
+ (void*)SurfaceUtils_nativeDetectSurfaceType},
+ {"nativeDetectSurfaceDataspace", "(Landroid/view/Surface;)I",
+ (void*)SurfaceUtils_nativeDetectSurfaceDataspace},
+ {"nativeDetectSurfaceDimens", "(Landroid/view/Surface;[I)I",
+ (void*)SurfaceUtils_nativeDetectSurfaceDimens},
+ {"nativeDetectSurfaceUsageFlags", "(Landroid/view/Surface;)J",
+ (void*)SurfaceUtils_nativeDetectSurfaceUsageFlags},
+ {"nativeGetSurfaceId", "(Landroid/view/Surface;)J", (void*)SurfaceUtils_nativeGetSurfaceId},
+};
+
+// Get all the required offsets in java class and register native functions
+int register_android_hardware_camera2_utils_SurfaceUtils(JNIEnv* env) {
+ // Register native functions
+ return RegisterMethodsOrDie(env, CAMERA_UTILS_CLASS_NAME, gCameraSurfaceUtilsMethods,
+ NELEM(gCameraSurfaceUtilsMethods));
+}
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 792c00572318..bdb4544f4aae 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -16,20 +16,21 @@
#define LOG_TAG "InputWindowHandle"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-#include "jni.h"
-#include <android_runtime/AndroidRuntime.h>
-#include <utils/threads.h>
+#include "android_hardware_input_InputWindowHandle.h"
#include <android/graphics/region.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <binder/IPCThreadState.h>
#include <gui/SurfaceControl.h>
+#include <nativehelper/JNIHelp.h>
#include <ui/Region.h>
+#include <utils/threads.h>
-#include "android_hardware_input_InputWindowHandle.h"
#include "android_hardware_input_InputApplicationHandle.h"
#include "android_util_Binder.h"
-#include <binder/IPCThreadState.h>
+#include "core_jni_helpers.h"
+#include "input/InputWindow.h"
+#include "jni.h"
namespace android {
@@ -113,10 +114,10 @@ bool NativeInputWindowHandle::updateInfo() {
mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
- mInfo.layoutParamsFlags = env->GetIntField(obj,
- gInputWindowHandleClassInfo.layoutParamsFlags);
- mInfo.layoutParamsType = env->GetIntField(obj,
- gInputWindowHandleClassInfo.layoutParamsType);
+ mInfo.flags = Flags<InputWindowInfo::Flag>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
+ mInfo.type = static_cast<InputWindowInfo::Type>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutNanos));
mInfo.frameLeft = env->GetIntField(obj,
@@ -157,8 +158,8 @@ bool NativeInputWindowHandle::updateInfo() {
gInputWindowHandleClassInfo.ownerPid);
mInfo.ownerUid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerUid);
- mInfo.inputFeatures = env->GetIntField(obj,
- gInputWindowHandleClassInfo.inputFeatures);
+ mInfo.inputFeatures = static_cast<InputWindowInfo::Feature>(
+ env->GetIntField(obj, gInputWindowHandleClassInfo.inputFeatures));
mInfo.displayId = env->GetIntField(obj,
gInputWindowHandleClassInfo.displayId);
mInfo.portalToDisplayId = env->GetIntField(obj,
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 9816d713c6dc..15a91107cbb1 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -342,11 +342,11 @@ static jlong android_view_MotionEvent_nativeInitialize(
return 0;
}
- MotionEvent* event;
+ std::unique_ptr<MotionEvent> event;
if (nativePtr) {
- event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event = std::unique_ptr<MotionEvent>(reinterpret_cast<MotionEvent*>(nativePtr));
} else {
- event = new MotionEvent();
+ event = std::make_unique<MotionEvent>();
}
PointerProperties pointerProperties[pointerCount];
@@ -355,7 +355,7 @@ static jlong android_view_MotionEvent_nativeInitialize(
for (jint i = 0; i < pointerCount; i++) {
jobject pointerPropertiesObj = env->GetObjectArrayElement(pointerPropertiesObjArray, i);
if (!pointerPropertiesObj) {
- goto Error;
+ return 0;
}
pointerPropertiesToNative(env, pointerPropertiesObj, &pointerProperties[i]);
env->DeleteLocalRef(pointerPropertiesObj);
@@ -363,7 +363,7 @@ static jlong android_view_MotionEvent_nativeInitialize(
jobject pointerCoordsObj = env->GetObjectArrayElement(pointerCoordsObjArray, i);
if (!pointerCoordsObj) {
jniThrowNullPointerException(env, "pointerCoords");
- goto Error;
+ return 0;
}
pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
env->DeleteLocalRef(pointerCoordsObj);
@@ -377,13 +377,7 @@ static jlong android_view_MotionEvent_nativeInitialize(
downTimeNanos, eventTimeNanos, pointerCount, pointerProperties,
rawPointerCoords);
- return reinterpret_cast<jlong>(event);
-
-Error:
- if (!nativePtr) {
- delete event;
- }
- return 0;
+ return reinterpret_cast<jlong>(event.release());
}
static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b7c5289043d6..c73441cbd4f9 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -101,6 +101,19 @@
#include "nativebridge/native_bridge.h"
+/* Functions in the callchain during the fork shall not be protected with
+ Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
+#else
+#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#else /* !__ARM_FEATURE_PAC_DEFAULT */
+#define NO_PAC_FUNC
+#endif /* __ARM_FEATURE_PAC_DEFAULT */
+
+
namespace {
// TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -1066,7 +1079,23 @@ static void ClearUsapTable() {
gUsapPoolCount = 0;
}
+NO_PAC_FUNC
+static void PAuthKeyChange(JNIEnv* env) {
+#ifdef __aarch64__
+ unsigned long int hwcaps = getauxval(AT_HWCAP);
+ if (hwcaps & HWCAP_PACA) {
+ const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
+ PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
+ if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
+ ALOGE("Failed to change the PAC keys: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "PAC key change failed.");
+ }
+ }
+#endif
+}
+
// Utility routine to fork a process from the zygote.
+NO_PAC_FUNC
static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -1117,6 +1146,7 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
}
// The child process.
+ PAuthKeyChange(env);
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
@@ -2052,6 +2082,7 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl
PreApplicationInit();
}
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits,
@@ -2104,6 +2135,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
return pid;
}
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -2175,6 +2207,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
* @param is_priority_fork Controls the nice level assigned to the newly created process
* @return
*/
+NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
jclass,
jint read_pipe_fd,
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index edafb0c19da8..ca4dc18689bc 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -208,6 +208,13 @@ message SecureSettingsProto {
optional Doze doze = 21;
optional SettingProto emergency_assistance_application = 22 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
+ message EmergencyResponse {
+ optional SettingProto panic_gesture_enabled = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ }
+
+ optional EmergencyResponse emergency_response = 83;
+
optional SettingProto enhanced_voice_privacy_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
message Gesture {
@@ -606,5 +613,5 @@ message SecureSettingsProto {
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 83;
+ // Next tag = 84;
}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 02213ed84f09..c21663811756 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -28,6 +28,7 @@ import "frameworks/base/core/proto/android/view/enums.proto";
import "frameworks/base/core/proto/android/view/surface.proto";
import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/typedef.proto";
package com.android.server.wm;
@@ -43,8 +44,8 @@ message WindowManagerServiceDumpProto {
optional string focused_app = 4;
optional IdentifierProto input_method_window = 5;
optional bool display_frozen = 6;
- optional int32 rotation = 7;
- optional int32 last_orientation = 8;
+ optional int32 rotation = 7 [(.android.typedef) = "android.view.Surface.Rotation"];
+ optional int32 last_orientation = 8 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
optional int32 focused_display_id = 9;
}
@@ -177,7 +178,7 @@ message DisplayContentProto {
repeated WindowTokenProto ime_windows = 8 [deprecated=true];
optional int32 dpi = 9;
optional .android.view.DisplayInfoProto display_info = 10;
- optional int32 rotation = 11;
+ optional int32 rotation = 11 [(.android.typedef) = "android.view.Surface.Rotation"];
optional ScreenRotationAnimationProto screen_rotation_animation = 12;
optional DisplayFramesProto display_frames = 13;
optional int32 surface_size = 14 [deprecated=true];
@@ -264,8 +265,8 @@ message TaskProto {
optional int32 display_id = 15;
optional int32 root_task_id = 16;
- optional int32 activity_type = 17;
- optional int32 resize_mode = 18;
+ optional int32 activity_type = 17 [(.android.typedef) = "android.app.WindowConfiguration.ActivityType"];
+ optional int32 resize_mode = 18 [(.android.typedef) = "android.appwidget.AppWidgetProviderInfo.ResizeModeFlags"];
optional int32 min_width = 19;
optional int32 min_height = 20;
@@ -351,7 +352,7 @@ message WindowStateProto {
optional .android.graphics.RectProto surface_position = 16;
optional int32 requested_width = 18;
optional int32 requested_height = 19;
- optional int32 view_visibility = 20;
+ optional int32 view_visibility = 20 [(.android.typedef) = "android.view.View.Visibility"];
optional int32 system_ui_visibility = 21;
optional bool has_surface = 22;
optional bool is_ready_for_display = 23;
@@ -424,7 +425,7 @@ message WindowContainerProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional ConfigurationContainerProto configuration_container = 1;
- optional int32 orientation = 2;
+ optional int32 orientation = 2 [(.android.typedef) = "android.content.pm.ActivityInfo.ScreenOrientation"];
optional bool visible = 3;
optional SurfaceAnimatorProto surface_animator = 4;
repeated WindowContainerChildProto children = 5;
diff --git a/core/proto/android/typedef.proto b/core/proto/android/typedef.proto
new file mode 100644
index 000000000000..be8742de5673
--- /dev/null
+++ b/core/proto/android/typedef.proto
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android;
+
+import "google/protobuf/descriptor.proto";
+
+extend google.protobuf.FieldOptions {
+ // Used to specify the IntDef annotation type so that ints
+ // can be associated with their string representation
+
+ // 60001 is a random field numbers assigned to the custom options
+ // numbers between 50000 and 99999 are reserved for internal use within individual organizations
+ optional string typedef = 60001;
+}
diff --git a/core/proto/android/view/windowlayoutparams.proto b/core/proto/android/view/windowlayoutparams.proto
index 272a24515367..64e6da852529 100644
--- a/core/proto/android/view/windowlayoutparams.proto
+++ b/core/proto/android/view/windowlayoutparams.proto
@@ -19,6 +19,7 @@ syntax = "proto2";
import "frameworks/base/core/proto/android/graphics/pixelformat.proto";
import "frameworks/base/core/proto/android/view/display.proto";
import "frameworks/base/core/proto/android/privacy.proto";
+import "frameworks/base/core/proto/android/typedef.proto";
package android.view;
option java_multiple_files = true;
@@ -27,15 +28,15 @@ option java_multiple_files = true;
message WindowLayoutParamsProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 type = 1;
+ optional int32 type = 1 [(.android.typedef) = "android.view.WindowManager.LayoutParams.WindowType"];
optional int32 x = 2;
optional int32 y = 3;
optional int32 width = 4;
optional int32 height = 5;
optional float horizontal_margin = 6;
optional float vertical_margin = 7;
- optional int32 gravity = 8;
- optional int32 soft_input_mode = 9;
+ optional int32 gravity = 8; // TODO (b/160129453): Add IntDef
+ optional int32 soft_input_mode = 9 [(.android.typedef) = "android.view.WindowManager.LayoutParams.SoftInputModeFlags"];
optional .android.graphics.PixelFormatProto.Format format = 10;
optional int32 window_animations = 11;
optional float alpha = 12;
@@ -53,17 +54,17 @@ message WindowLayoutParamsProto {
optional float preferred_refresh_rate = 16;
optional int32 preferred_display_mode_id = 17;
optional bool has_system_ui_listeners = 18;
- optional uint32 input_feature_flags = 19;
+ optional uint32 input_feature_flags = 19; // TODO (b/160129453): Add IntDef
optional int64 user_activity_timeout = 20;
optional DisplayProto.ColorMode color_mode = 23;
- optional uint32 flags = 24;
- optional uint32 private_flags = 26;
- optional uint32 system_ui_visibility_flags = 27;
- optional uint32 subtree_system_ui_visibility_flags = 28;
- optional uint32 appearance = 29;
- optional uint32 behavior = 30;
- optional uint32 fit_insets_types = 31;
- optional uint32 fit_insets_sides = 32;
+ optional uint32 flags = 24 [(.android.typedef) = "android.view.WindowManager.LayoutParams.Flags"];
+ optional uint32 private_flags = 26 [(.android.typedef) = "android.view.WindowManager.LayoutParams.PrivateFlags"];
+ optional uint32 system_ui_visibility_flags = 27; // TODO (b/160129453): Add IntDef
+ optional uint32 subtree_system_ui_visibility_flags = 28; // TODO (b/160129453): Add IntDef
+ optional uint32 appearance = 29 [(.android.typedef) = "android.view.WindowInsetsController.Appearance"];
+ optional uint32 behavior = 30 [(.android.typedef) = "android.view.WindowInsetsController.Behavior"];
+ optional uint32 fit_insets_types = 31 [(.android.typedef) = "android.view.WindowInsets.Type.InsetsType"];
+ optional uint32 fit_insets_sides = 32 [(.android.typedef) = "android.view.WindowInsets.Side.InsetsSide"];
optional bool fit_ignore_visibility = 33;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0985fea3d26a..ef50fc8e2b6e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -227,6 +227,8 @@
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED" />
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY" />
<protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED" />
<protected-broadcast
android:name="com.android.bluetooth.BluetoothMapContentObserver.action.MESSAGE_SENT" />
<protected-broadcast
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6bc69cd3b56c..3b61c367e1bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n\n•Skakel Donkertema aan\n•Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk hulle\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batterybespaarder doen die volgende om batterylewe te verleng:\n\n•Skakel Donkertema aan\n•Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk hulle"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batterybespaarder doen die volgende om die batterylewe te verleng:\n\n• Skakel Donkertema aan\n• Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk dit\n\n"<annotation id="url">"Kom meer te wete"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batterybespaarder doen die volgende om batterylewe te verleng:\n\n• Skakel Donkertema aan\n• Skakel agtergrondaktiwiteit, sommige visuele effekte en ander kenmerke, soos \"Ok Google\", af of beperk dit"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databespaarder verhoed sommige programme om data in die agtergrond te stuur of te aanvaar om datagebruik te help verminder. \'n Program wat jy tans gebruik kan by data ingaan, maar sal dit dalk minder gereeld doen. Dit kan byvoorbeeld beteken dat prente nie wys totdat jy op hulle tik nie."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Skakel Databespaarder aan?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Skakel aan"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index f5d7246b96a3..e80720d9a2b8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1884,8 +1884,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"‏لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\".\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"‏لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"‏لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n·تفعيل \"المظهر الداكن\"\n إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"\n\n\n"<annotation id="url">"مزيد من المعلومات"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"‏لإطالة عمر البطارية، تعمل ميزة \"توفير شحن البطارية\" على:\n\n• تفعيل \"المظهر الداكن\"\n• إيقاف أو حظر النشاط في الخلفية وبعض التأثيرات المرئية والميزات الأخرى، مثل \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"للمساعدة في خفض استخدام البيانات، تمنع ميزة \"توفير البيانات\" بعض التطبيقات من إرسال البيانات وتلقّيها في الخلفية. يمكن للتطبيقات المتاحة لديك الآن استخدام البيانات، ولكن لا يمكنها الإكثار من ذلك. وهذا يعني أن الصور مثلاً لا تظهر حتى تنقر عليها."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"هل تريد تفعيل توفير البيانات؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"تفعيل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index e7acc3b845da..881a1278666c 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ, বেটাৰী সঞ্চয়কাৰীয়ে:\n\n•গাঢ় ৰঙৰ থীম অন কৰে\n•পটভূমিৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল প্ৰভাৱ আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সেইবোৰ সীমাবদ্ধ কৰে\n\n"<annotation id="url">"অধিক জানক"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ, বেটাৰী সঞ্চয়কাৰীয়ে:\n\n•গাঢ় ৰঙৰ থীম অন কৰে\n•পটভূমিৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল প্ৰভাৱ আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সেইবোৰ সীমাবদ্ধ কৰে"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ, বেটাৰী সঞ্চয়কাৰীয়ে:\n\n•গাঢ় ৰঙৰ থীম অন কৰে\n•নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সেইবোৰ সীমাবদ্ধ কৰে\n\n"<annotation id="url">"অধিক জানক"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"বেটাৰীৰ জীৱনকাল বৃদ্ধি কৰিবলৈ বেটাৰী সঞ্চয়কাৰীয়ে:\n\n• গাঢ় ৰঙৰ থীম অন কৰে\n• নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট আৰু “Hey Google”ৰ দৰে অন্য সুবিধাসমূহ অফ কৰে অথবা সীমাবদ্ধ কৰে"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ডেটা ব্য়ৱহাৰ মাত্ৰা কম কৰিবৰ বাবে ডেটা সঞ্চয়কাৰীয়ে কিছুমান এপক নেপথ্য়ত ডেটা প্ৰেৰণ বা সংগ্ৰহ কৰাত বাধা প্ৰদান কৰে। আপুনি বৰ্তমান ব্য়ৱহাৰ কৰি থকা এটা এপে ডেটা ব্য়ৱহাৰ কৰিব পাৰে, কিন্তু সঘনাই এই কার্য কৰিব নোৱাৰিব পাৰে। ইয়াৰ অৰ্থ এইয়ে হ\'ব পাৰে যে, উদাহৰণস্বৰূপে, আপুনি নিটিপা পর্যন্ত প্ৰতিচ্ছবিসমূহ দেখুওৱা নহ’ব।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সঞ্চয়কাৰী অন কৰিবনে?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"অন কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 3240808f2eb9..6408ef629b36 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n•Qaranlıq temanı aktiv edir\n•Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n•Qaranlıq temanı aktiv edir\n•Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n• Qaranlıq temanı aktiv edir\n• Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır\n\n"<annotation id="url">"Ətraflı məlumat"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batareyanın ömrünü artırmaq üçün Enerjiyə Qənaət funksiyası:\n\n• Qaranlıq temanı aktiv edir\n• Arxa fondakı fəaliyyəti, bəzi vizual effektləri və “Hey Google” kimi digər funksiyaları deaktiv edir və ya məhdudlaşdırır"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data istifadəsini azalatmaq üçün, Data Qanaəti bəzi tətbiqlərin arxafonda data göndərməsinin və qəbulunun qarşısını alır. Hazırda işlətdiyiniz tətbiq dataya daxil ola bilər, ancaq bunu tez-tez edə bilməz. Bu o deməkdir ki, məsələn, Siz üzərinə tıklamadıqca o şəkillər göstərilməyəcək."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Data Qənaəti aktiv edilsin?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivləşdirin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 590bd4f14363..ff70218e657a 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n•uključuje tamnu temu\n•isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n•uključuje tamnu temu\n•isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n• uključuje tamnu temu\n• isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Da bi se produžilo trajanje baterije, Ušteda baterije:\n\n• uključuje tamnu temu\n• isključuje ili ograničava aktivnosti u pozadini, neke vizuelne efekte i druge funkcije, na primer, „Ok Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Želite da uključite Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 8da6a75d7100..ed781fb25698 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n•·уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n• уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n•·уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\"\n\n"<annotation id="url">"Даведацца больш"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду:\n\n• уключае цёмную тэму;\n• выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі, напрыклад \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"У рэжыме \"Эканомія трафіка\" фонавая перадача для некаторых праграмам адключана. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але радзей, чым звычайна. Напрыклад, відарысы могуць не загружацца, пакуль вы не націсніце на іх."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Уключыць Эканомію трафіка?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Уключыць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0b4055935722..f089d62707b5 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n•·включва тъмната тема;\n•·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n• включва тъмната тема;\n• изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n•·включва тъмната тема;\n•·изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“.\n\n"<annotation id="url">"Научете повече"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"С цел удължаване на живота на батерията режимът за запазването ѝ:\n\n• включва тъмната тема;\n• изключва или ограничава активността на заден план, някои визуални ефекти и други функции, като например „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"С цел намаляване на преноса на данни функцията за икономия на данни не позволява на някои приложения да изпращат или получават данни на заден план. Понастоящем използвано от вас приложение може да използва данни, но по-рядко. Това например може да означава, че изображенията не се показват, докато не ги докоснете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ще вкл. ли „Икономия на данни“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включване"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 7f219ac5eb37..9b2c093bd178 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n\n•গাঢ় থিম চালু করে\n•ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমিত করে\n\n"<annotation id="url">"আরও জানুন"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ব্যাটারি আরও বেশিক্ষণ চালাতে, ব্যাটারি সেভার:\n\n•গাঢ় থিম চালু করে\n•ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট এবং “হ্যালো Google”-এর মতো অন্যান্য ফিচার বন্ধ বা সীমিত করে"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ডেটার ব্যবহার কমাতে সহায়তা করার জন্য, ডেটা সেভার ব্যাকগ্রাউন্ডে কিছু অ্যাপ্লিকেশনকে ডেটা পাঠাতে বা গ্রহণ করতে বাধা দেয়৷ আপনি বর্তমানে এমন একটি অ্যাপ্লিকেশন ব্যবহার করছেন যেটি ডেটা অ্যাক্সেস করতে পারে, তবে সেটি কমই করে৷ এর ফলে যা হতে পারে, উদাহরণস্বরূপ, আপনি ছবির উপর ট্যাপ না করা পর্যন্ত সেগুলি দেখানো হবে না৷"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ডেটা সেভার চালু করবেন?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"চালু করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 176f8309507d..6be331355766 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n•Uključuje Tamnu temu\n•Isključuje ili ograničava aktivnosti u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\"\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n•Uključuje Tamnu temu\n•Isključuje ili ograničava aktivnosti u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n• Uključuje Tamnu temu\n• Isključuje ili ograničava aktivnosti u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\"\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Radi produženja vijeka trajanja baterije, Ušteda baterije:\n\n• Uključuje Tamnu temu\n• Isključuje ili ograničava aktivnost u pozadini, određene vizuelne efekte i druge funkcije kao što je \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Radi smanjenja prijenosa podataka, Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali će to činiti rjeđe. Naprimjer, to može značiti da se slike ne prikazuju dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0d7341d817ef..5fadc92d2970 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\".\n\n"<annotation id="url">"Més informació"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Per allargar la durada de la bateria, el mode Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Per allargar la durada de la bateria, la funció Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\".\n\n"<annotation id="url">"Més informació"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Per allargar la durada de la bateria, la funció Estalvi de bateria fa el següent:\n\n• Activa el tema fosc.\n• Desactiva o restringeix l\'activitat en segon pla, alguns efectes visuals i altres funcions com \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per reduir l\'ús de dades, la funció Economitzador de dades evita que determinades aplicacions enviïn o rebin dades en segon pla. L\'aplicació que estiguis fent servir podrà accedir a les dades, però menys sovint. Això vol dir, per exemple, que les imatges no es mostraran fins que no les toquis."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activar l\'Economitzador de dades?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activa"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ccaf0b775f7e..856176455150 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Spořič baterie za účelem úspory energie:\n\n• zapne tmavý motiv,\n• vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“\n\n"<annotation id="url">"Další informace"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Spořič baterie za účelem úspory energie:\n\n• zapne tmavý motiv,\n• vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Spořič baterie za účelem úspory energie:\n\n• Zapne tmavý motiv.\n• Vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“.\n\n"<annotation id="url">"Další informace"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Spořič baterie za účelem úspory energie:\n\n• Zapne tmavý motiv.\n• Vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 0bb19aa86de4..1b3dab2352f4 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n•Aktiverer Mørkt tema\n•Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n•Aktiverer Mørkt tema\n•Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n• Aktiverer Mørkt tema\n• Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\"\n\n"<annotation id="url">"Få flere oplysninger"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batterisparefunktionen gør følgende for at spare på batteriet:\n\n• Aktiverer Mørkt tema\n• Deaktiverer eller begrænser aktivitet i baggrunden, visse visuelle effekter og andre funktioner som f.eks. \"Hey Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du aktivere Datasparefunktion?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivér"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index dc0b6c3681de..0cc15d208233 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -935,7 +935,7 @@
<string name="save_password_label" msgid="9161712335355510035">"Bestätigen"</string>
<string name="double_tap_toast" msgid="7065519579174882778">"Tipp: Zum Vergrößern und Verkleinern doppeltippen"</string>
<string name="autofill_this_form" msgid="3187132440451621492">"AutoFill"</string>
- <string name="setup_autofill" msgid="5431369130866618567">"AutoFill konfig."</string>
+ <string name="setup_autofill" msgid="5431369130866618567">"Autom.Ausfüll.konf."</string>
<string name="autofill_window_title" msgid="4379134104008111961">"Mit <xliff:g id="SERVICENAME">%1$s</xliff:g> automatisch ausfüllen"</string>
<string name="autofill_address_name_separator" msgid="8190155636149596125">" "</string>
<string name="autofill_address_summary_name_format" msgid="3402882515222673691">"$1$2$3"</string>
@@ -1104,7 +1104,7 @@
<string name="selectTextMode" msgid="3225108910999318778">"Text auswählen"</string>
<string name="undo" msgid="3175318090002654673">"Rückgängig machen"</string>
<string name="redo" msgid="7231448494008532233">"Wiederholen"</string>
- <string name="autofill" msgid="511224882647795296">"AutoFill"</string>
+ <string name="autofill" msgid="511224882647795296">"Automatisches Ausfüllen"</string>
<string name="textSelectionCABTitle" msgid="5151441579532476940">"Textauswahl"</string>
<string name="addToDictionary" msgid="8041821113480950096">"Zum Wörterbuch hinzufügen"</string>
<string name="deleteText" msgid="4200807474529938112">"Löschen"</string>
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Der Energiesparmodus sorgt für eine längere Akkulaufzeit:\n\n• Das dunkle Design wird aktiviert\n• Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen wie \"Ok Google\" werden abgeschaltet oder eingeschränkt\n\n"<annotation id="url">"Weitere Informationen"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Der Energiesparmodus sorgt für eine längere Akkulaufzeit:\n\n• Das dunkle Design wird aktiviert\n• Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen wie \"Ok Google\" werden abgeschaltet oder eingeschränkt"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"Der Datensparmodus verhindert zum einen, dass manche Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datensparmodus aktivieren?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivieren"</string>
@@ -1928,13 +1930,13 @@
<string name="time_picker_prompt_label" msgid="303588544656363889">"Uhrzeit eingeben"</string>
<string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"In den Texteingabemodus wechseln, um die Uhrzeit einzugeben."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"In den Uhrzeitmodus wechseln, um die Uhrzeit einzugeben."</string>
- <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"AutoFill-Optionen"</string>
- <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Für AutoFill speichern"</string>
+ <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Optionen für automatisches Ausfüllen"</string>
+ <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Für \"Automatisches Ausfüllen\" speichern"</string>
<string name="autofill_error_cannot_autofill" msgid="6528827648643138596">"Inhalte können nicht automatisch ausgefüllt werden"</string>
- <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Keine AutoFill-Vorschläge"</string>
+ <string name="autofill_picker_no_suggestions" msgid="1076022650427481509">"Keine Vorschläge für automatisches Ausfüllen"</string>
<plurals name="autofill_picker_some_suggestions" formatted="false" msgid="6651883186966959978">
- <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> AutoFill-Vorschläge</item>
- <item quantity="one">1 AutoFill-Vorschlag</item>
+ <item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> Vorschläge für automatisches Ausfüllen</item>
+ <item quantity="one">1 Vorschlag für automatisches Ausfüllen</item>
</plurals>
<string name="autofill_save_title" msgid="7719802414283739775">"In "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" speichern?"</string>
<string name="autofill_save_title_with_type" msgid="3002460014579799605">"<xliff:g id="TYPE">%1$s</xliff:g> in "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" speichern?"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 7d346e3aad36..e790c9a071a9 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n\n•Ενεργοποιεί το Σκούρο θέμα\n•Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή Hey Google\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Για την επέκταση της διάρκειας ζωής της μπαταρίας, η Εξοικονόμηση μπαταρίας:\n\n•Ενεργοποιεί το Σκούρο θέμα\n•Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή Hey Google."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n\n• Ενεργοποιεί το Σκούρο θέμα\n• Απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες όπως την εντολή Hey Google\n\n"<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Για την επέκταση της διάρκειας ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας:\n\n• Ενεργοποιεί το Σκούρο θέμα\n• Απενεργοποιεί ή περιορίζει τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ και άλλες λειτουργίες, όπως την εντολή Hey Google"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Προκειμένου να μειωθεί η χρήση δεδομένων, η Εξοικονόμηση δεδομένων αποτρέπει την αποστολή ή λήψη δεδομένων από ορισμένες εφαρμογές στο παρασκήνιο. Μια εφαρμογή που χρησιμοποιείτε αυτήν τη στιγμή μπορεί να χρησιμοποιήσει δεδομένα αλλά με μικρότερη συχνότητα. Για παράδειγμα, οι εικόνες μπορεί να μην εμφανίζονται μέχρι να τις πατήσετε."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ενεργ.Εξοικονόμησης δεδομένων;"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ενεργοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 77c6d4e55937..0f1566b10347 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index e8452bbbb691..84b3ce1ffc22 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like \"Hey Google\"\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like \"Hey Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you\'re currently using can access data, but may do so less frequently. This may mean, for example, that images don\'t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ee1716840136..d9a2bdba5f10 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 4733daf0008b..1209f2bc4318 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'\n\n"<annotation id="url">"Learn more"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"To extend battery life, Battery Saver:\n\n•Turns on Dark theme\n•Turns off or restricts background activity, some visual effects and other features like \'Hey Google\'"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"To extend battery life, Battery Saver:\n\n• Turns on Dark theme\n• Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Turn on Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Turn on"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index dee052668a1e..7f29fd463403 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎Updated by your admin‎‏‎‎‏‎"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎Deleted by your admin‎‏‎‎‏‎"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎OK‎‏‎‎‏‎"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎•Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎•Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="url">"‎‏‎‎‏‏‏‎Learn more‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
- <string name="battery_saver_description" msgid="8587408568232177204">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎•Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎•Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‎"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="url">"‎‏‎‎‏‏‏‎Learn more‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎• Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‎"</string>
<string name="data_saver_description" msgid="4995164271550590517">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‏‎‏‎To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.‎‏‎‎‏‎"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎Turn on Data Saver?‎‏‎‎‏‎"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‏‏‎‎Turn on‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 8276684ea50f..f8ead2795a9a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para extender la duración de la batería, el Ahorro de batería hace lo siguiente:\n\n•Activa el Tema oscuro.\n•Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n\n•Activa el Tema oscuro.\n•Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n\n• Activa el Tema oscuro.\n• Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para extender la duración de batería, el Ahorro de batería hace lo siguiente:\n\n• Activa el Tema oscuro.\n• Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Hey Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para reducir el uso de datos, el modo Ahorro de datos evita que algunas apps envíen y reciban datos en segundo plano. La app que estés usando podrá acceder a los datos, pero con menor frecuencia. De esta forma, por ejemplo, las imágenes no se mostrarán hasta que las presiones."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Deseas activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index d312d859a58c..741c89f0e5d9 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para que la batería dure más, el modo Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro\n•Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para que la batería dure más, el modo Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro\n• Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para que la batería dure más, Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro.\n• Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\".\n\n"<annotation id="url">"Más información"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para que la batería dure más, Ahorro de batería hace lo siguiente:\n\n• Activa el tema oscuro.\n• Desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones, como \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"El modo Ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que puede reducir el uso de datos. Una aplicación activa puede acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar Ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 94d6e5e3251d..d724046c2a73 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n\n• Lülitab sisse tumeda teema.\n• Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Ok Google”) või piirab neid."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Lülitada andmemahu säästja sisse?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 506069caa934..24d3eef619e8 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\".\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Desaktibatu edo murriztu egiten ditu atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk, hala nola \"Ok Google\".\n\n"<annotation id="url">"Lortu informazio gehiago"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Bateriaren iraupena luzatzeko, erabili bateria-aurrezlea:\n\n• Gai iluna aktibatzen du.\n• Atzeko planoko jarduerak, zenbait efektu bisual eta beste eginbide batzuk desaktibatzen edo murrizten ditu, hala nola \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datuen erabilera murrizteko, atzeko planoan datuak bidaltzea eta jasotzea galarazten die datu-aurrezleak aplikazio batzuei. Une honetan erabiltzen ari zaren aplikazioak atzitu egin ahal izango ditu datuak, baina baliteke maiztasun txikiagoarekin atzitzea. Horrela, adibidez, baliteke irudiak ez erakustea haiek sakatu arte."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Datu-aurrezlea aktibatu nahi duzu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktibatu"</string>
@@ -1926,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"Ezarri ordua"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"Idatzi balio duen ordu bat"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"Idatzi ordua"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Ordua idazteko, aldatu testua idazteko metodora."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Ordua idazteko, aldatu testua idazteko modura."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Aldatu erloju modura ordua zehazteko."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Betetze automatikoaren aukerak"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Gorde betetze automatikoarekin erabiltzeko"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f0440b517377..b0b533858b3a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n\n•«طرح زمینه تیره» را روشن می‌کند\n•فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n\n•«طرح زمینه تیره» را روشن می‌کند\n•فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n\n• «طرح زمینه تیره» را روشن می‌کند\n• فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مانند «Ok Google» را خاموش یا محدود می‌کند\n\n"<annotation id="url">"بیشتر بدانید"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"‏برای افزایش عمر باتری، «بهینه‌سازی باتری»:\n\n• «طرح زمینه تیره» را روشن می‌کند\n• فعالیت پس‌زمینه، برخی جلوه‌های بصری، و دیگر ویژگی‌ها مثل «Ok Google» را خاموش یا محدود می‌کند"</string>
<string name="data_saver_description" msgid="4995164271550590517">"«صرفه‌جویی داده»، برای کمک به کاهش مصرف داده، از ارسال و دریافت داده در پس‌زمینه ازطرف بعضی برنامه‌ها جلوگیری می‌کند. برنامه‌ای که درحال‌حاضر استفاده می‌کنید می‌تواند به داده‌ها دسترسی داشته باشد اما دفعات دسترسی آن محدود است.این یعنی، برای مثال، تصاویر تازمانی‌که روی آن‌ها ضربه نزنید نشان داده نمی‌شوند."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"«صرفه‌جویی داده» روشن شود؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"روشن کردن"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index bb7cac0803ab..8d5aea9e427e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Hei Google)."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Ok Google).\n\n"<annotation id="url">"Lue lisää"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Parantaakseen akunkestoa Virransäästö\n\n•·laittaa tumman teeman päälle\n•·laittaa pois päältä tai rajoittaa taustatoimintoja, joitakin visuaalisia tehosteita ja muita ominaisuuksia (esim. Ok Google)."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Data Saver estää joitakin sovelluksia lähettämästä tai vastaanottamasta tietoja taustalla, jotta datan käyttöä voidaan vähentää. Käytössäsi oleva sovellus voi yhä käyttää dataa, mutta se saattaa tehdä niin tavallista harvemmin. Tämä voi tarkoittaa esimerkiksi sitä, että kuva ladataan vasta, kun kosketat sitä."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Otetaanko Data Saver käyttöön?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ota käyttöön"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 1b530a4806ff..d3323d733824 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Pour prolonger l\'autonomie de la pile, l\'économiseur de pile effectue les actions suivantes :\n\n•·Active le thème sombre\n•·Désactive ou limite l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme « Ok Google »"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour aider à diminuer l\'utilisation des données, la fonctionnalité Économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Une application que vous utilisez actuellement peut accéder à des données, mais peut le faire moins souvent. Cela peut signifier, par exemple, que les images ne s\'affichent pas jusqu\'à ce que vous les touchiez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 80c8f645b217..4a1646f8ba30 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n·• active le thème sombre\n·• désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Ok Google\"\n\n"<annotation id="url">"En savoir plus"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n·• active le thème sombre\n • désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n·• active le thème sombre ;\n·• désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Hey Google\".\n\n"<annotation id="url">"En savoir plus"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n\n• active le thème sombre ;\n • désactive ou restreint les activités en arrière-plan, certains effets visuels et d\'autres fonctionnalités, comme \"Hey Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index bd328b542966..54e17faf9b4a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n•Activa o tema escuro\n•Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\"\n\n"<annotation id="url">"Máis información"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n•Activa o tema escuro\n•Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n• Activa o tema escuro.\n• Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\".\n\n"<annotation id="url">"Máis información"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para aumentar a duración da batería, a función Aforro de batería fai o seguinte:\n\n• Activa o tema escuro\n• Desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións, como \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para contribuír a reducir o uso de datos, o aforro de datos impide que algunhas aplicacións envíen ou reciban datos en segundo plano. Cando esteas utilizando unha aplicación, esta poderá acceder aos datos, pero é posible que o faga con menos frecuencia. Por exemplo, é posible que as imaxes non se mostren ata que as toques."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Queres activar o aforro de datos?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 8a959ef4170b..7410c667dc8e 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n\n•ઘેરી થીમ ચાલુ કરે છે\n•બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “ઓકે Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે\n\n"<annotation id="url">"વધુ જાણો"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"બૅટરીની આવરદા વધારવા માટે, બૅટરી સેવર:\n\n•ઘેરી થીમ ચાલુ કરે છે\n•બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ અને “ઓકે Google” જેવી અન્ય સુવિધાઓ બંધ અથવા પ્રતિબંધિત કરે છે"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ડેટા વપરાશને ઘટાડવામાં સહાય માટે, ડેટા સેવર કેટલીક ઍપને બૅકગ્રાઉન્ડમાં ડેટા મોકલવા અથવા પ્રાપ્ત કરવાથી અટકાવે છે. તમે હાલમાં ઉપયોગ કરી રહ્યાં છો તે ઍપ ડેટાને ઍક્સેસ કરી શકે છે, પરંતુ તે આ ક્યારેક જ કરી શકે છે. આનો અર્થ એ હોઈ શકે છે, ઉદાહરણ તરીકે, છબીઓ ત્યાં સુધી પ્રદર્શિત થશે નહીં જ્યાં સુધી તમે તેને ટૅપ નહીં કરો."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ડેટા સેવર ચાલુ કરીએ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ચાલુ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4f3d89009323..06d495f9cfec 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n•गहरे रंग वाली थीम चालू करता है\n•बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या उन्हें बंद कर देता है"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n• गहरे रंग वाली थीम चालू करता है\n• बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या इन्हें बंद कर देता है\n\n"<annotation id="url">"ज़्यादा जानें"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"बैटरी लाइफ़ बढ़ाने के लिए, बैटरी सेवर:\n\n• गहरे रंग वाली थीम चालू करता है\n• बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और \"Hey Google\" जैसी दूसरी सुविधाएं इस्तेमाल करने से रोकता है या इन्हें बंद कर देता है"</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटा खर्च को कम करने के लिए, डेटा बचाने की सेटिंग कुछ ऐप्लिकेशन को बैकग्राउंड में डेटा भेजने या डेटा पाने से रोकती है. फ़िलहाल, आप जिस ऐप्लिकेशन का इस्तेमाल कर रहे हैं वह डेटा ऐक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन पर टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"चालू करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 503eab8da081..a1b303ee7cd4 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\".\n\n"<annotation id="url">"Saznajte više"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Da bi se produljilo trajanje baterije, Štednja baterije:\n\n• Uključuje Tamnu temu.\n• Isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke kao što je \"Hey Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Da bi se smanjio podatkovni promet, značajka Štednja podatkovnog prometa onemogućuje nekim aplikacijama slanje ili primanje podataka u pozadini. Aplikacija koju trenutačno upotrebljavate može pristupiti podacima, no možda će to činiti rjeđe. To može značiti da se, na primjer, slike neće prikazivati dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Uključiti Štednju podatkovnog prometa?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Uključi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index bdd12d2a8418..ff0d4709c970 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat.\n\n"<annotation id="url">"További információ"</annotation>"."</string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében a következőket teszi:\n\n• Bekapcsolja a sötét témát.\n• Kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket, az „Ok Google” parancsot és egyéb funkciókat."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Az adatforgalom csökkentése érdekében az Adatforgalom-csökkentő megakadályozza, hogy egyes alkalmazások adatokat küldjenek vagy fogadjanak a háttérben. Az Ön által jelenleg használt alkalmazások hozzáférhetnek az adatokhoz, de csak ritkábban. Ez például azt jelentheti, hogy a képek csak rákoppintás után jelennek meg."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bekapcsolja az Adatforgalom-csökkentőt?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bekapcsolás"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index f1b474775082..05c447d50f7b 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը.\n\n•Միացնում է մուգ թեման։\n•Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը:"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը՝\n\n• Միացնում է մուգ թեման։\n• Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը։\n\n"<annotation id="url">"Իմանալ ավելին"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Մարտկոցի աշխատաժամանակը երկարացնելու համար «Մարտկոցի տնտեսում» գործառույթը՝\n\n• Միացնում է մուգ թեման։\n• Անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ և այլ գործառույթներ, օրինակ՝ «Ok Google» հրահանգը։"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Թրաֆիկի տնտեսման ռեժիմում որոշ հավելվածների համար տվյալների ֆոնային փոխանցումն անջատված է։ Հավելվածը, որն օգտագործում եք, կարող է տվյալներ փոխանցել և ստանալ, սակայն ոչ այնքան հաճախ: Օրինակ՝ պատկերները կցուցադրվեն միայն դրանց վրա սեղմելուց հետո։"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Միացնե՞լ թրաֆիկի տնտեսումը"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Միացնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 10ea70ee78ff..a6f68d171ec4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n\n•Mengaktifkan Tema gelap\n•Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai:\n\n•Mengaktifkan Tema gelap\n•Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai akan:\n\n• Mengaktifkan Tema gelap\n• Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”\n\n"<annotation id="url">"Pelajari lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Untuk memperpanjang masa pakai baterai, Penghemat Baterai akan:\n\n• Mengaktifkan Tema gelap\n• Menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual, dan fitur lain seperti “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah diketuk."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Aktifkan Penghemat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktifkan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 7db90ebcaf7a..92f6f2488d18 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•Kveikir á dökku þema\n•Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“\n\n"<annotation id="url">"Frekari upplýsingar"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•Kveikir á dökku þema\n•Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•·Kveikir á dökku þema\n•·Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“\n\n"<annotation id="url">"Frekari upplýsingar"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Til að auka rafhlöðuendingu gerir rafhlöðusparnaður eftirfarandi:\n\n•·Kveikir á dökku þema\n•·Slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika eins og „Ok Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan getur verið, svo dæmi sé tekið, að myndir eru ekki birtar fyrr en þú ýtir á þær."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Kveikja á gagnasparnaði?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Kveikja"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d617a3a4cf17..8f857fa32c73 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n•Attiva il tema scuro\n•Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n• Attiva il tema scuro\n• Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Per estendere la durata della batteria, la funzionalità di risparmio energetico:\n\n• Attiva il tema scuro\n• Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index d1072a1de2c1..e5b458615197 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"‏כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n•מפעילה עיצוב כהה\n•מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google\n\n"<annotation id="url">"מידע נוסף"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"‏כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n•מפעילה עיצוב כהה\n•מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"‏כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n• מפעילה עיצוב כהה\n• מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google\n\n"<annotation id="url">"למידע נוסף"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"‏כדי להאריך את חיי הסוללה, התכונה \'חיסכון בסוללה\':\n\n• מפעילה עיצוב כהה\n• מכבה או מגבילה פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות כמו Ok Google"</string>
<string name="data_saver_description" msgid="4995164271550590517">"‏כדי לסייע בהפחתת השימוש בנתונים, חוסך הנתונים (Data Saver) מונע מאפליקציות מסוימות שליחה או קבלה של נתונים ברקע. אפליקציה שבה נעשה שימוש כרגע יכולה לגשת לנתונים, אבל בתדירות נמוכה יותר. המשמעות היא, למשל, שתמונות יוצגו רק לאחר שמקישים עליהן."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"להפעיל את חוסך הנתונים?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"הפעל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index eabf37c50878..27889fb9b512 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n•ダークテーマをオンにする\n•バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n•ダークテーマをオンにする\n•バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能をオフにする、または制限する"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n• ダークテーマを ON にする\n• バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する\n\n"<annotation id="url">"詳細"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"電池を長持ちさせるためにバッテリー セーバーが行う操作:\n\n• ダークテーマを ON にする\n• バックグラウンド アクティビティ、一部の視覚効果や、「OK Google」などの機能を OFF にする、または制限する"</string>
<string name="data_saver_description" msgid="4995164271550590517">"データセーバーは、一部のアプリによるバックグラウンドでのデータ送受信を停止することでデータ使用量を抑制します。使用中のアプリからデータを送受信することはできますが、その頻度は低くなる場合があります。この影響として、たとえば画像はタップしないと表示されないようになります。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"データセーバーを ON にしますか?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ON にする"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index a67cdc033736..6547185c4beb 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგველი:\n\n•ჩართავს ბნელ თემას\n•გამორთავს ან ზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგველი:\n\n•ჩართავს ბნელ თემას\n•გამორთავს ან ზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგველი:\n\n• ჩართავს ბნელ თემას\n• გამორთავს ან ზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“\n\n"<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგი:\n\n• ჩართავს ბნელ თემას\n• გამორთავს ან შეზღუდავს ფონურ აქტივობას, გარკვეულ ვიზუალურ ეფექტებს და სხვა ფუნქციებს, მაგალითად, „Hey Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"მობილური ინტერნეტის მოხმარების შემცირების მიზნით, მონაცემთა დამზოგველი ზოგიერთ აპს ფონურ რეჟიმში მონაცემთა გაგზავნასა და მიღებას შეუზღუდავს. თქვენ მიერ ამჟამად გამოყენებული აპი მაინც შეძლებს მობილურ ინტერნეტზე წვდომას, თუმცა ამას ნაკლები სიხშირით განახორციელებს. ეს ნიშნავს, რომ, მაგალითად, სურათები არ გამოჩნდება მანამ, სანამ მათ საგანგებოდ არ შეეხებით."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ჩაირთოს მონაცემთა დამზოგველი?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ჩართვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 351790d44b7b..3d53912ad62b 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n\n•қараңғы тақырыпты іске қосады;\n•фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n\n•қараңғы тақырыпты іске қосады;\n•фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді немесе шектейді."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Батарея жұмысының ұзақтығын арттыру үшін Battery Saver:\n\n•қараңғы тақырыпты іске қосады;\n•фондық әрекеттерді, кейбір көрнекі әсерлерді және \"Ok Google\" сияқты басқа да функцияларды өшіреді не шектейді.\n\n"<annotation id="url">"Толығырақ"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Батарея ұзағырақ жұмыс істеуі үшін, Battery Saver:\n\n• қараңғы тақырыпты қосады;\n•фондық жұмысты, кейбір визуалды әсерлерді және \"Ok Google\" сияқты басқа функцияларды өшіреді не шектейді."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дерек шығынын азайту үшін Data Saver функциясы кейбір қолданбаларға деректерді фондық режимде жіберуге және алуға жол бермейді. Ашық тұрған қолданба деректерді пайдаланады, бірақ шектеулі шамада (мысалы, кескіндер оларды түрткенге дейін көрсетілмейді)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Data Saver функциясын қосу керек пе?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Қосу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 80be70a6a2a8..760d256ca62c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំថ្ម៖\n\n•បើករចនាប័ទ្មងងឹត\n•បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Ok Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់​បន្ថែម"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំថ្ម៖\n\n•បើករចនាប័ទ្មងងឹត\n•បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Ok Google” ជាដើម"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម កម្មវិធី​សន្សំថ្ម៖\n\n• បើករចនាប័ទ្មងងឹត\n• បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Ok Google” ជាដើម\n\n"<annotation id="url">"ស្វែងយល់​បន្ថែម"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ដើម្បី​បង្កើនកម្រិត​ថាមពលថ្ម មុខងារ​សន្សំថ្ម៖\n\n• បើករចនាប័ទ្មងងឹត\n• បិទ ឬដាក់កំហិតលើ​សកម្មភាពផ្ទៃខាងក្រោយ ឥទ្ធិពលរូបភាពមួយចំនួន និងមុខងារផ្សេងទៀត​ដូចជា “Ok Google” ជាដើម"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ដើម្បីជួយកាត់បន្ថយការប្រើប្រាស់ទិន្នន័យ កម្មវិធីសន្សំសំចៃទិន្នន័យរារាំងកម្មវិធីមួយចំនួនមិនឲ្យបញ្ជូន ឬទទួលទិន្នន័យនៅផ្ទៃខាងក្រោយទេ។ កម្មវិធីដែលអ្នកកំពុងប្រើនាពេលបច្ចុប្បន្នអាចចូលប្រើប្រាស់​ទិន្នន័យបាន ប៉ុន្តែអាចនឹងមិនញឹកញាប់ដូចមុនទេ។ ឧទាហរណ៍ រូបភាពមិនបង្ហាញទេ លុះត្រាតែអ្នកប៉ះរូបភាពទាំងនោះ។"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"បើកកម្មវិធីសន្សំសំចៃទិន្នន័យ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"បើក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 69a402ef0c77..6513481089ad 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n•ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n•ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n•ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n•ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n• ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n•ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “ಹೇ Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ\n\n"<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ವಿಸ್ತರಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್:\n\n• ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ\n• ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು “Ok Google” ನಂತಹ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡುವ ನಿಟ್ಟಿನಲ್ಲಿ, ಡೇಟಾ ಸೇವರ್ ಕೆಲವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಡೇಟಾ ಕಳುಹಿಸುವುದನ್ನು ಅಥವಾ ಸ್ವೀಕರಿಸುವುದನ್ನು ತಡೆಯುತ್ತದೆ. ನೀವು ಪ್ರಸ್ತುತ ಬಳಸುತ್ತಿರುವ ಅಪ್ಲಿಕೇಶನ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಬಹುದು ಆದರೆ ಪದೇ ಪದೇ ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಇದರರ್ಥ, ಉದಾಹರಣೆಗೆ, ನೀವು ಅವುಗಳನ್ನು ಟ್ಯಾಪ್ ಮಾಡುವವರೆಗೆ ಆ ಚಿತ್ರಗಳು ಕಾಣಿಸಿಕೊಳ್ಳುವುದಿಲ್ಲ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ಡೇಟಾ ಸೇವರ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ಆನ್‌ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 421ae440a741..db8d379c4083 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n\n•어두운 테마를 사용 설정합니다.\n•백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n\n•어두운 테마를 사용 설정합니다.\n•백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"배터리 수명을 늘리기 위해 절전 모드가 다음과 같이 작동합니다.\n\n• 어두운 테마를 사용 설정합니다.\n• 백그라운드 활동, 일부 시각 효과 및 \'Hey Google\'과 같은 기타 기능을 사용 중지하거나 제한합니다.\n\n"<annotation id="url">"자세히 알아보기"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"배터리 수명을 연장하기 위해 절전 모드가 다음과 같이 작동합니다.\n\n• 어두운 테마를 사용 설정합니다.\n• 백그라운드 활동, 일부 시각 효과 및 \'Hey Google\' 등의 기타 기능을 사용 중지하거나 제한합니다."</string>
<string name="data_saver_description" msgid="4995164271550590517">"데이터 사용량을 줄이기 위해 데이터 절약 모드는 일부 앱이 백그라운드에서 데이터를 전송하거나 수신하지 못하도록 합니다. 현재 사용 중인 앱에서 데이터에 액세스할 수 있지만 빈도가 줄어듭니다. 예를 들면, 이미지를 탭하기 전에는 이미지가 표시되지 않습니다."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"데이터 절약 모드를 사용 설정하시겠습니까?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"사용 설정"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index f1bea56a62fd..c208396b278a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батареянын мөөнөтүн узартуу үчүн, Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n\n•Караңгы теманы күйгүзөт\n•Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Батареянын иштешин узартуу үчүн, Батареяны үнөмдөөчү режим:\n\n•Караңгы теманы күйгүзөт\n•Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Батареянын мөөнөтүн узартуу үчүн, Батареяны үнөмдөгүч режими төмөнкүлөрдү аткарат:\n\n• Караңгы теманы күйгүзөт\n• Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт\n\n"<annotation id="url">"Кеңири маалымат"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Батареянын мөөнөтүн узартуу үчүн, Батареяны үнөмдөгүч режими:\n\n• Караңгы теманы күйгүзөт\n• Фондогу аракеттерди, айрым визуалдык эффекттерди жана \"Окей Google\" сыяктуу башка функцияларды өчүрөт же чектейт"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Трафикти үнөмдөө режиминде айрым колдонмолор дайын-даректерди фондо өткөрө алышпайт. Учурда сиз пайдаланып жаткан колдонмо дайын-даректерди жөнөтүп/ала алат, бирок адаттагыдан азыраак өткөргөндүктөн, анын айрым функциялары талаптагыдай иштебей коюшу мүмкүн. Мисалы, сүрөттөр басылмайынча жүктөлбөйт."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Трафикти үнөмдөө режимин иштетесизби?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Күйгүзүү"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index f9456a7ff721..f388cfaed0ca 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n•ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n•ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n• ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n• ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”\n\n"<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ເພື່ອຍືດອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດແບັດເຕີຣີຈະ:\n\n• ເປີດໃຊ້ຮູບແບບສີສັນມືດ\n• ປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກດ້ານພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດອື່ນໆ ເຊັ່ນ: “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ເພື່ອຊ່ວຍຫຼຸດຜ່ອນການນຳໃຊ້ຂໍ້ມູນ, ຕົວປະຢັດອິນເຕີເນັດຈະປ້ອງກັນບໍ່ໃຫ້ບາງແອັບສົ່ງ ຫຼື ຮັບຂໍ້ມູນໃນພື້ນຫຼັງ. ແອັບໃດໜຶ່ງທີ່ທ່ານກຳລັງໃຊ້ຢູ່ຈະສາມາດເຂົ້າເຖິງຂໍ້ມູນໄດ້ ແຕ່ອາດເຂົ້າເຖິງໄດ້ຖີ່ໜ້ອຍລົງ. ນີ້ອາດໝາຍຄວາມວ່າ ຮູບພາບຕ່າງໆອາດບໍ່ສະແດງຈົນກວ່າທ່ານຈະແຕະໃສ່ກ່ອນ."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ເປີດຕົວປະຢັດອິນເຕີເນັດບໍ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ເປີດໃຊ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index de0f7478a604..d68cd8d3c822 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“.\n\n"<annotation id="url">"Sužinokite daugiau"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Kad akumuliatorius veiktų ilgiau, Akumuliatoriaus tausojimo priemonė:\n\n• įjungia tamsiąją temą;\n• išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas funkcijas, pvz., „Ok Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Kad padėtų sumažinti duomenų naudojimą, Duomenų taupymo priemonė neleidžia kai kurioms programoms siųsti ar gauti duomenų fone. Šiuo metu naudojama programa gali pasiekti duomenis, bet tai bus daroma rečiau. Tai gali reikšti, kad, pvz., vaizdai nebus pateikiami, jei jų nepaliesite."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Įj. Duomenų taupymo priemonę?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Įjungti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 818d61c421c4..9462c227a3cf 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas darbības fonā, noteikti vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas darbības fonā, noteikti vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 5c720a3315a4..aee1fca01cb1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n•вклучува темна тема;\n•исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Ok Google“.\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n•вклучува темна тема;\n•исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Ok Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n• вклучува темна тема\n• исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“\n\n"<annotation id="url">"Дознајте повеќе"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"За да го продолжи траењето на батеријата, „Штедачот на батерија“:\n\n• вклучува темна тема\n• исклучува или ограничува активност во заднина, некои визуелни ефекти и други функции како „Hey Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"За да се намали користењето интернет, „Штедачот на интернет“ спречува дел од апликациите да испраќаат или да примаат податоци во заднина. Одредена апликација што ја користите ќе може да користи интернет, но можеби тоа ќе го прави поретко. Ова значи, на пример, дека сликите нема да се прикажуваат додека не ги допрете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Да се вклучи „Штедач на интернет“?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Вклучи"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b4982ebdeeca..c43503664123 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n\n•ഡാർക്ക് തീം ഓണാക്കും\n•പശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും\n\n"<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ബാറ്ററി ലെെഫ് വികസിപ്പിക്കാൻ, \'ബാറ്ററി ലാഭിക്കൽ\':\n\n•ഡാർക്ക് തീം ഓണാക്കും\n•പശ്ചാത്തല പ്രവർത്തനം, ചില വിഷ്വൽ ഇഫക്റ്റുകൾ, “ഹേയ് Google” പോലുള്ള മറ്റ് ഫീച്ചറുകൾ എന്നിവ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ഡാറ്റാ ഉപയോഗം കുറയ്ക്കാൻ സഹായിക്കുന്നതിനായി പശ്ചാത്തലത്തിൽ ഡാറ്റ അയയ്ക്കുകയോ സ്വീകരിക്കുകയോ ചെയ്യുന്നതിൽ നിന്ന് ചില ആപ്പുകളെ ഡാറ്റാ സേവർ തടയുന്നു. നിങ്ങൾ നിലവിൽ ഉപയോഗിക്കുന്ന ഒരു ആപ്പിന് ഡാറ്റ ആക്‌സസ് ചെയ്യാനാകും, എന്നാൽ വല്ലപ്പോഴും മാത്രമെ സംഭവിക്കുന്നുള്ളു. ഇതിനർത്ഥം, ഉദാഹരണമായി നിങ്ങൾ ടാപ്പ് ചെയ്യുന്നത് വരെ ചിത്രങ്ങൾ പ്രദ‍‍‍ർശിപ്പിക്കുകയില്ല എന്നാണ്."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ഡാറ്റ സേവർ ഓണാക്കണോ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ഓണാക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 02b9de5c1b95..1472c4e9f178 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч:\n\n•Бараан загварыг асаана\n•Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарлана\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч:\n\n•Бараан загварыг асаана\n•Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарлана"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Батарейн ажиллах хугацааг уртасгахын тулд Батарей хэмнэгч:\n\n•Бараан загварыг асаадаг\n•Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг\n\n"<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Батарей хэмнэгч нь батарейн ажиллах хугацааг уртасгахын тулд:\n\n• Бараан загварыг асаадаг\n• Арын үйл ажиллагаа, зарим визуал эффект болон “Hey Google” зэрэг бусад онцлогийг унтрааж эсвэл хязгаарладаг"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Дата ашиглалтыг багасгахын тулд дата хэмнэгч нь ар талд ажиллаж буй зарим апп-н өгөгдлийг илгээх болон авахаас сэргийлдэг. Таны одоогийн ашиглаж буй апп нь өгөгдөлд хандах боломжтой хэдий ч тогтмол хандахгүй. Энэ нь жишээлбэл зургийг товших хүртэл харагдахгүй гэсэн үг юм."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Дата хэмнэгчийг асаах уу?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Асаах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f5db8ccdb36b..6695de6c7a33 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"बॅटरीचे आयुष्य वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर:\n\n•गडद थीम सुरू करते\n•बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि \"Ok Google\" यांसारखी वैशिष्ट्ये बंद किंवा मर्यादित करते.\n\n"<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर:\n\n• गडद थीम सुरू करते\n• बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि “Ok Google” यांसारखी इतर वैशिष्ट्ये बंद किंवा मर्यादित करते"</string>
<string name="data_saver_description" msgid="4995164271550590517">"डेटाचा वापर कमी करण्यात मदत करण्यासाठी काही अ‍ॅप्सना बॅकग्राउंडमध्ये डेटा पाठवण्यास किंवा मिळवण्यास डेटा सर्व्हर प्रतिबंध करतो. तुम्ही सध्या वापरत असलेले अ‍ॅप डेटा अ‍ॅक्सेस करू शकते, पण तसे खूप कमी वेळा होते. याचाच अर्थ असा की, तुम्ही इमेजवर टॅप करेपर्यंत त्या डिस्प्ले होणार नाहीत असे होऊ शकते."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेव्हर सुरू करायचे?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सुरू करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0b905a6cb095..c8f37c305ff7 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n•Menghidupkan Tema gelap\n•Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Ok Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n•Menghidupkan Tema gelap\n•Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n• Menghidupkan Tema gelap\n• Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri lain seperti “Ok Google”\n\n"<annotation id="url">"Ketahui lebih lanjut"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Untuk melanjutkan hayat bateri, Penjimat Bateri:\n\n•Menghidupkan Tema gelap\n• Mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual dan ciri-ciri lain seperti “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Untuk membantu mengurangkan penggunaan data, Penjimat Data menghalang sesetengah apl daripada menghantar atau menerima data di latar. Apl yang sedang digunakan boleh mengakses data tetapi mungkin tidak secara kerap. Perkara ini mungkin bermaksud bahawa imej tidak dipaparkan sehingga anda mengetik pada imej itu, contohnya."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Hidupkan Penjimat Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Hidupkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 793a6f9d2bee..dcb4e3cfc634 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က- \n\n•မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n•နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က- \n\n•မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n•နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က- \n\n• မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n• နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်\n\n"<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က-\n\n•မှောင်သည့် အပြင်အဆင်ကို ဖွင့်သည်\n•နောက်ခံလုပ်ဆောင်ချက်၊ ပြသမှုဆိုင်ရာ အထူးပြုလုပ်ချက်အချို့နှင့် “Ok Google” ကဲ့သို့ အခြား ဝန်ဆောင်မှုများကို ပိတ်သည် သို့မဟုတ် ကန့်သတ်သည်"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ဒေတာအသုံးလျှော့ချနိုင်ရန်အတွက် အက်ပ်များကို နောက်ခံတွင် ဒေတာပို့ခြင်းနှင့် လက်ခံခြင်းမပြုရန် \'ဒေတာချွေတာမှု\' စနစ်က တားဆီးထားပါသည်။ ယခုအက်ပ်ဖြင့် ဒေတာအသုံးပြုနိုင်သော်လည်း အကြိမ်လျှော့၍သုံးရပါမည်။ ဥပမာ၊ သင်က မတို့မချင်း ပုံများပေါ်လာမည် မဟုတ်ပါ။"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ဒေတာချွေတာမှုစနစ် ဖွင့်မလား။"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ဖွင့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 5db133874d0b..6926d659ed3f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slår på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slår på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slår på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»\n\n"<annotation id="url">"Finn ut mer"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"For å forlenge batterilevetiden gjør Batterisparing dette:\n\n• Slår på mørkt tema\n• Slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner, for eksempel «Hey Google»"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Datasparing hindrer noen apper fra å sende og motta data i bakgrunnen, for å redusere dataforbruket. Aktive apper kan bruke data, men kanskje ikke så mye som ellers – for eksempel vises ikke bilder før du trykker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vil du slå på Datasparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Slå på"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 355ee94ac3b7..20eac82eb23d 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ\n\n"<annotation id="url">"थप जान्नुहोस्"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ब्याट्रीको आयु बढाउन ब्याट्री सेभरले:\n\n•अँध्यारो थिम सक्रिय गर्छ\n•पृष्ठभूमिका गतिविधि, केही दृश्यात्मक प्रभाव तथा “Hey Google” जस्ता अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"डेटाको प्रयोगलाई कम गर्न डेटा सर्भरले केही एपलाई पृष्ठभूमिमा डेटा पठाउन वा प्राप्त गर्न दिँदैन। तपाईंले हाल प्रयोग गरिरहनुभएको अनु्प्रयोगले डेटा चलाउन सक्छ, तर पहिला भन्दा कम अन्तरालमा मात्र। उदाहरणका लागि, तपाईले छविहरूमा ट्याप नगरेसम्म ती छविहरू देखिँदैनन्।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"डेटा सेभर सक्रिय गर्ने हो?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"सक्रिय गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ed57f7ffc89d..904c90665229 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n•Het donkere thema aanzetten\n•Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitzetten of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n•Het donkere thema aanzetten\n•Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitzetten of beperken"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n• Het donkere thema inschakelen\n• Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken\n\n"<annotation id="url">"Meer informatie"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batterijbesparing doet het volgende om de batterijduur te verlengen:\n\n• Het donkere thema inschakelen.\n• Achtergrondactiviteit, bepaalde visuele effecten en andere functies (zoals \'Hey Google\') uitschakelen of beperken."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Databesparing beperkt het datagebruik door te voorkomen dat sommige apps gegevens verzenden of ontvangen op de achtergrond. De apps die je open hebt, kunnen nog steeds data verbruiken, maar doen dit minder vaak. Afbeeldingen worden dan bijvoorbeeld niet weergegeven totdat je erop tikt."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Databesparing aanzetten?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Inschakelen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index c60f5e166a4a..b0a4d47d562a 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଅପଡେଟ୍‍ କରିଛନ୍ତି"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଡିଲିଟ୍‍ କରିଛନ୍ତି"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ୍ ଅଛି"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ\n\n"<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ବ୍ୟାଟେରୀ ଲାଇଫ୍ ବଢ଼ାଇବାକୁ ବ୍ୟାଟେରୀ ସେଭର୍:\n\n•ଗାଢ଼ା ଥିମ୍ ଚାଲୁ କରେ\n•ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବ ଏବଂ “Hey Google” ପରି ଅନ୍ୟ ଫିଚରଗୁଡ଼ିକୁ ବନ୍ଦ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"ଡାଟା ବ୍ୟବହାର କମ୍‍ କରିବାରେ ସାହାଯ୍ୟ କରିବାକୁ, ଡାଟା ସେଭର୍‍ ବ୍ୟାକ୍‌ଗ୍ରାଉଣ୍ଡରେ ଡାଟା ପଠାଇବା କିମ୍ବା ପ୍ରାପ୍ତ କରିବାକୁ କିଛି ଆପ୍‍କୁ ବାରଣ କରେ। ଆପଣ ବର୍ତ୍ତମାନ ବ୍ୟବହାର କରୁଥିବା ଆପ୍‍, ଡାଟା ଆକ୍ସେସ୍‍ କରିପାରେ, କିନ୍ତୁ ଏହା କମ୍‍ ଥର କରିପାରେ। ଏହାର ଅର୍ଥ ହୋଇପାରେ ଯେମିତି ଆପଣ ଇମେଜଗୁଡ଼ିକୁ ଟାପ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ସେଗୁଡ଼ିକ ଡିସପ୍ଲେ ହୁଏ ନାହିଁ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ଡାଟା ସେଭର୍‌ ଚାଲୁ କରିବେ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ଚାଲୁ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 11f3cacee7e3..346ee9a476c7 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n•ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n•ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n•ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n•ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n• ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n• ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n\n• ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ\n• ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ਚਾਲੂ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 990ce70a92d4..7d2795e2db0f 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n•włącza tryb ciemny\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n•włącza tryb ciemny\n•wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Aby wydłużyć czas pracy na baterii, funkcja Oszczędzanie baterii:\n\n•włącza tryb ciemny,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”.\n\n"<annotation id="url">"Więcej informacji"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii:\n\n• włącza tryb ciemny,\n• wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje, np. „OK Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Oszczędzanie danych uniemożliwia niektórym aplikacjom wysyłanie i odbieranie danych w tle, zmniejszając w ten sposób ich użycie. Aplikacja, z której w tej chwili korzystasz, może uzyskiwać dostęp do danych, ale rzadziej. Może to powodować, że obrazy będą się wyświetlać dopiero po kliknięciu."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Włączyć Oszczędzanie danych?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Włącz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 0883b7cdc0b0..4fec5b3779a2 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n• ativa o tema escuro;\n• desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n• ativa o tema escuro;\n• desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 2a958dc080b6..5f6fb5cf553c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n•Ativa o tema escuro.\n•Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saber mais"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n•Ativa o tema escuro.\n•Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n•Ativa o tema escuro.\n•Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para prolongar a autonomia da bateria, a Poupança de bateria:\n\n• Ativa o tema escuro.\n•·Desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades como \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir a utilização de dados, a Poupança de dados impede que algumas aplicações enviem ou recebam dados em segundo plano. Uma determinada app que esteja a utilizar atualmente pode aceder aos dados, mas é possível que o faça com menos frequência. Isto pode significar, por exemplo, que as imagens não são apresentadas até que toque nas mesmas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Pretende ativar a Poupança de dados?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 0883b7cdc0b0..4fec5b3779a2 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n•ativa o tema escuro;\n•desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n• ativa o tema escuro;\n• desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\".\n\n"<annotation id="url">"Saiba mais"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para prolongar a duração da carga, a \"Economia de bateria\":\n\n• ativa o tema escuro;\n• desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos, como o \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Para ajudar a reduzir o uso de dados, a Economia de dados impede que alguns apps enviem ou recebam dados em segundo plano. Um app que você esteja usando no momento pode acessar dados, mas com menos frequência. Isso pode fazer com que imagens não sejam exibidas até que você toque nelas."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ativar \"Economia de dados\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0a30432b4c1d..a0e35985b142 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administratorul dvs."</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n•·activează tema întunecată;\n•·dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n• activează tema întunecată;\n• dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n•·activează tema întunecată;\n•·dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”.\n\n"<annotation id="url">"Aflați mai multe"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Pentru a mări autonomia bateriei, Economisirea bateriei:\n\n• activează tema întunecată;\n• dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții, cum ar fi „Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Pentru a contribui la reducerea utilizării de date, Economizorul de date împiedică unele aplicații să trimită sau să primească date în fundal. O aplicație pe care o folosiți poate accesa datele, însă mai rar. Aceasta poate însemna, de exemplu, că imaginile se afișează numai după ce le atingeți."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Activați Economizorul de date?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Activați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2590f05aafa7..1a65847fecf4 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\").\n\n"<annotation id="url">"Подробнее…"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Чтобы продлить время работы от батареи, в режиме энергосбережения:\n\n• включается тёмная тема;\n• отключаются или ограничиваются фоновые процессы, некоторые визуальные эффекты и другие функции (например, распознавание команды \"Окей, Google\")."</string>
<string name="data_saver_description" msgid="4995164271550590517">"В режиме экономии трафика фоновая передача данных для некоторых приложений отключена. Приложение, которым вы пользуетесь, может получать и отправлять данные, но реже, чем обычно. Например, изображения могут не загружаться, пока вы не нажмете на них."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Включить экономию трафика?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Включить"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 4224d510bc74..db759f62b8ae 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්‍රියාත්මක කරයි\n•පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්‍රියාත්මක කරයි\n•පසුබිමේ ක්‍රියාකාරකම, සමහර දෘෂ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්‍රියාත්මක කරයි\n•පසුබිමේ ක්‍රියාකාරකම, සමහර දෘශ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි\n\n"<annotation id="url">"තව දැන ගන්න"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"බැටරියේ ජීව කාලය දික් කිරීමට, බැටරි සුරැකුම:\n\n•අඳුරු තේමාව ක්‍රියාත්මක කරයි\n•පසුබිමේ ක්‍රියාකාරකම, සමහර දෘශ්‍ය ප්‍රයෝග සහ “Hey Google” වැනි වෙනත් විශේෂාංග ක්‍රියාවිරහිත කරයි නැතහොත් අවහිර කරයි"</string>
<string name="data_saver_description" msgid="4995164271550590517">"දත්ත භාවිතය අඩු කිරීමට උදවු වීමට, දත්ත සුරැකුම සමහර යෙදුම් පසුබිමින් දත්ත යැවීම සහ ලබා ගැනීම වළක්වයි. ඔබ දැනට භාවිත කරන යෙදුමකට දත්ත වෙත පිවිසීමට හැකිය, නමුත් එසේ කරන්නේ කලාතුරකින් විය හැකිය. මෙයින් අදහස් වන්නේ, උදාහරණයක් ලෙස, එම රූප ඔබ ඒවාට තට්ටු කරන තෙක් සංදර්ශනය නොවන බවය."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"දත්ත සුරැකුම ක්‍රියාත්මක කරන්නද?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ක්‍රියාත්මක කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7621cf1755b6..5f80364368eb 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n•vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového slova „Hey Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n• vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového slova „Hey Google“."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n• vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového výrazu „Hey Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Šetrič batérie predlžuje výdrž batérie:\n\n• zapnutím tmavého motívu;\n• vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad kľúčového výrazu „Hey Google“."</string>
<string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 34e71161cb37..4e3705976e5f 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n•Vklopi temno temo,\n•izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n•Vklopi temno temo,\n•izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n•vklopi temno temo,\n•izklopi ali omeji dejavnost v ozadju, nekatere vizualne učinke in druge funkcije, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Funkcija varčevanja z energijo baterije podaljša čas delovanja baterije tako:\n\n• vklopi temno temo;\n• izklopi ali omeji dejavnost v ozadju, nekatere vizualne učinke in druge funkcije, kot je »Hey Google«."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Vklop"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index bf77b84ca85d..30e75558bb76 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n•Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”\n\n"<annotation id="url">"Mëso më shumë"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n•Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n• Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”\n\n"<annotation id="url">"Mëso më shumë"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Për të rritur kohëzgjatjen e baterisë, \"Kursyesi i baterisë\":\n\n• Aktivizon \"Temën e errët\"\n• Çaktivizon ose kufizon aktivitetin në sfond, disa efekte vizuale dhe veçori të tjera si “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivizo"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f3b057853f3c..c043a8d37ecc 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1815,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Да би се продужило трајање батерије, Уштеда батерије:\n\n•укључује тамну тему\n•искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Да би се продужило трајање батерије, Уштеда батерије:\n\n•укључује тамну тему\n•искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Да би се продужило трајање батерије, Уштеда батерије:\n\n• укључује тамну тему\n• искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“\n\n"<annotation id="url">"Сазнајте више"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Да би се продужило трајање батерије, Уштеда батерије:\n\n• укључује тамну тему\n• искључује или ограничава активности у позадини, неке визуелне ефекте и друге функције, на пример, „Ок Google“"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Да би се смањила потрошња података, Уштеда података спречава неке апликације да шаљу или примају податке у позадини. Апликација коју тренутно користите може да приступа подацима, али ће то чинити ређе. На пример, слике се неће приказивати док их не додирнете."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Желите да укључите Уштеду података?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Укључи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e0e54ed0434c..565fc5357f3d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”\n\n"<annotation id="url">"Läs mer"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batterisparläget förlänger batteritiden genom att:\n\n• aktivera mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batterisparläget förlänger batteritiden genom att\n\n• aktivera mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”\n\n"<annotation id="url">"Läs mer"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batterisparläget förlänger batteritiden genom att\n\n• aktivera Mörkt tema\n• inaktivera eller begränsa aktivitet i bakgrunden, vissa visuella effekter och andra funktioner, som ”Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Med databesparing kan du minska dataanvändningen genom att hindra en del appar från att skicka eller ta emot data i bakgrunden. Appar som du använder kan komma åt data, men det sker kanske inte lika ofta. Detta innebär t.ex. att bilder inte visas förrän du trycker på dem."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vill du aktivera Databesparing?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aktivera"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c2642ffe37bc..fbf4ccae2e4a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n•Huwasha Mandhari meusi\n•Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n•Huwasha Mandhari meusi\n•Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n• Huwasha Mandhari meusi\n• Huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\"\n\n"<annotation id="url">"Pata maelezo zaidi"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Ili kuongeza muda wa matumizi ya betri, Kiokoa Betri:\n\n• Huwasha Mandhari meusi\n• Huzima au kudhibiti shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vingine kama vile \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ili kusaidia kupunguza matumizi ya data, Kiokoa Data huzuia baadhi ya programu kupokea na kutuma data chinichini. Programu ambayo unatumia sasa inaweza kufikia data, lakini si kila wakati. Kwa mfano, haitaonyesha picha hadi utakapozifungua."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Ungependa Kuwasha Kiokoa Data?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Washa"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 5ff6d4bdcf82..731a796a9d08 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n•டார்க் தீமினை ஆன் செய்யும்\n•பின்னணி செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Hey Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n•டார்க் தீமினை ஆன் செய்யும்\n•பின்னணி செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Hey Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n• டார்க் தீமினை ஆன் செய்யும்\n• பின்னணி செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Ok Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்\n\n"<annotation id="url">"மேலும் அறிக"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"பேட்டரி நிலையை நீட்டிப்பதற்காக, பேட்டரி சேமிப்பான்:\n\n• டார்க் தீமினை ஆன் செய்யும்\n• பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபெக்ட்கள், “Ok Google” போன்ற பிற அம்சங்களை ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்"</string>
<string name="data_saver_description" msgid="4995164271550590517">"டேட்டா உபயோகத்தைக் குறைப்பதற்கு உதவ, பின்புலத்தில் டேட்டாவை அனுப்புவது அல்லது பெறுவதிலிருந்து சில ஆப்ஸை டேட்டா சேமிப்பான் தடுக்கும். தற்போது பயன்படுத்தும் ஆப்ஸானது எப்போதாவது டேட்டாவை அணுகலாம். எடுத்துக்காட்டாக, படங்களை நீங்கள் தட்டும் வரை அவை காட்டப்படாது."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"டேட்டா சேமிப்பானை இயக்கவா?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"இயக்கு"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6d39248a8069..e1a6d131ae16 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1792,8 +1792,10 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి, బ్యాటరీ సేవర్ వీటిని చేస్తుంది:\n\n•ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది\n•బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లతో పాటు “Ok Google” వంటి ఇతర ఫీచర్‌లను ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది\n\n"<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"బ్యాటరీ జీవితకాలాన్ని పెంచడానికి, బ్యాటరీ సేవర్ వీటిని చేస్తుంది:\n\n•ముదురు రంగు రూపాన్ని ఆన్ చేస్తుంది\n•బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లతో పాటు “Ok Google” వంటి ఇతర ఫీచర్‌లను ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది"</string>
+ <!-- no translation found for battery_saver_description_with_learn_more (4424488535318105801) -->
+ <skip />
+ <!-- no translation found for battery_saver_description (6794188153647295212) -->
+ <skip />
<string name="data_saver_description" msgid="4995164271550590517">"డేటా వినియోగాన్ని తగ్గించడంలో డేటా సేవర్ సహాయకరంగా ఉంటుంది. బ్యాక్‌గ్రౌండ్‌లో కొన్ని యాప్‌లు డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తోన్న యాప్‌, డేటాను యాక్సెస్ చేయగలదు. కానీ త‌క్కువ సార్లు మాత్ర‌మే అలా చేయవచ్చు. ఉదాహరణకు, మీరు నొక్కే వరకు ఫోటోలు ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"డేటా సేవర్‌ను ఆన్ చేయాలా?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"ఆన్ చేయి"</string>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 3ecb1dddd916..0382dd3b9103 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -42,4 +42,13 @@
<!-- Allow SystemUI to show the shutdown dialog -->
<bool name="config_showSysuiShutdown">true</bool>
+
+ <!-- Control the behavior when the user long presses the power button.
+ 0 - Nothing
+ 1 - Global actions menu
+ 2 - Power off (with confirmation)
+ 3 - Power off (without confirmation)
+ 4 - Go to voice assist
+ 5 - Go to assistant (Settings.Secure.ASSISTANT -->
+ <integer name="config_longPressOnPowerBehavior">3</integer>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 13a5e3894a2b..6773014ec2f8 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n•เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n•เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n• เปิดธีมมืด\n•ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n\n• เปิดธีมมืด\n• ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น \"Ok Google\""</string>
<string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7e7f86a3c915..da3e4373382a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n•I-on ang Madilim na tema\n•I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n•I-on ang Madilim na tema\n•I-off o paghigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”\n\n"<annotation id="url">"Matuto pa"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Para patagalin ang baterya, ginagawa ng Pangtipid sa Baterya na:\n\n• I-on ang Madilim na tema\n• I-off o paghihigpitan ang aktibidad sa background, ilang visual effect, at iba pang feature gaya ng “Hey Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Upang makatulong na mabawasan ang paggamit ng data, pinipigilan ng Data Saver ang ilang app na magpadala o makatanggap ng data sa background. Maaaring mag-access ng data ang isang app na ginagamit mo sa kasalukuyan, ngunit mas bihira na nito magagawa iyon. Halimbawa, maaaring hindi lumabas ang mga larawan hangga\'t hindi mo nata-tap ang mga ito."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"I-on ang Data Saver?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"I-on"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index b7af87e38fcb..bf17f6c360d4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n•Koyu temayı açar\n•Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n•Koyu temayı açar\n•Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n• Koyu temayı açar\n• Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar\n\n"<annotation id="url">"Daha fazla bilgi"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Pil ömrünü uzatmak için Pil Tasarrufu:\n\n• Koyu temayı açar\n• Arka plan etkinliğini, bazı görsel efektleri ve \"Ok Google\" gibi diğer özellikleri kapatır veya kısıtlar"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Veri kullanımını azaltmaya yardımcı olması için Veri Tasarrufu, bazı uygulamaların arka planda veri göndermesini veya almasını engeller. Şu anda kullandığınız bir uygulama veri bağlantısına erişebilir, ancak bunu daha seyrek yapabilir. Bu durumda örneğin, siz resimlere dokunmadan resimler görüntülenmez."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Veri Tasarrufu açılsın mı?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Aç"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 0842221b1ee8..9464efa043f0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1838,8 +1838,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n•вмикає темну тему;\n•припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\".\n\n"<annotation id="url">"Докладніше"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n•вмикає темну тему;\n•припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\"."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n• вмикає темну тему;\n• припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\".\n\n"<annotation id="url">"Докладніше"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Щоб подовжити час роботи акумулятора, режим енергозбереження:\n\n• вмикає темну тему;\n• припиняє або обмежує фонову активність, вимикає деякі візуальні ефекти та інші енергозатратні функції, зокрема команду \"Ok Google\"."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Щоб зменшити використання трафіку, функція \"Заощадження трафіку\" не дозволяє деяким додаткам надсилати чи отримувати дані у фоновому режимі. Поточний додаток зможе отримувати доступ до таких даних, але рідше. Наприклад, зображення не відображатиметься, доки ви не торкнетеся його."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Увімкнути заощадження трафіку?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Увімкнути"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3f5eb3e0d3f7..0d76d017b08d 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n\n•گہری تھیم کو آن کرتی ہے\n•پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n\n•گہری تھیم کو آن کرتی ہے\n•پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور:\n\n• گہری تھیم کو آن کرتی ہے\n• پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے\n\n"<annotation id="url">"مزید جانیں"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"‏بیٹری لائف کو بڑھانے کے لیے، بیٹری سیور: \n\n• گہری تھیم کو آن کرتی ہے\n• پس منظر کی سرگرمی، کچھ ویژوئل اثرات اور دیگر خصوصیات جیسے کہ \"Ok Google\" کو آف یا محدود کرتی ہے"</string>
<string name="data_saver_description" msgid="4995164271550590517">"ڈیٹا کے استعمال کو کم کرنے میں مدد کیلئے، ڈیٹا سیور پس منظر میں کچھ ایپس کو ڈیٹا بھیجنے یا موصول کرنے سے روکتی ہے۔ آپ جو ایپ فی الحال استعمال کر رہے ہیں وہ ڈیٹا تک رسائی کر سکتی ہے مگر ہو سکتا ہے ایسا اکثر نہ ہو۔ اس کا مطلب مثال کے طور پر یہ ہو سکتا ہے کہ تصاویر تھپتھپانے تک ظاہر نہ ہوں۔"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"ڈیٹا سیور آن کریں؟"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"آن کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index be21f7b8df15..76d2c609b63d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n•Tungi mavzuni yoqadi\n•Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n•Tungi mavzuni yoqadi\n•Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n• Tungi mavzuni yoqadi\n• Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi\n\n"<annotation id="url">"Batafsil"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Batareya quvvatini uzaytirish uchun Quvvat tejash funksiyasi:\n\n• Tungi mavzuni yoqadi\n• Fondagi harakatlar, vizual effektlar va “Hey Google” kabi boshqa funksiyalarni faolsizlantiradi"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Trafik tejash rejimida ayrim ilovalar uchun orqa fonda internetdan foydalanish imkoniyati cheklanadi. Siz ishlatayotgan ilova zaruratga qarab internet-trafik sarflashi mumkin, biroq cheklangan miqdorda. Masalan, rasmlar ustiga bosmaguningizcha ular yuklanmaydi."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Trafik tejash yoqilsinmi?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Yoqish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 33675da1fd38..9f44841f573c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n•Bật Giao diện tối\n•Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n•Bật Giao diện tối\n•Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n• Bật Giao diện tối\n• Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”\n\n"<annotation id="url">"Tìm hiểu thêm"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Để tăng thời lượng pin, Trình tiết kiệm pin sẽ:\n\n• Bật Giao diện tối\n• Tắt hoặc hạn chế hoạt động chạy trong nền, một số hiệu ứng hình ảnh và các tính năng khác như lệnh “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Để giúp giảm mức sử dụng dữ liệu, Trình tiết kiệm dữ liệu sẽ chặn một số ứng dụng gửi hoặc nhận dữ liệu trong nền. Ứng dụng mà bạn hiện sử dụng có thể dùng dữ liệu nhưng tần suất sẽ giảm. Ví dụ: hình ảnh sẽ không hiển thị cho đến khi bạn nhấn vào hình ảnh đó."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Bật Trình tiết kiệm dữ liệu?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7da8f15b4a44..32ac0cf297c4 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”\n\n"<annotation id="url">"了解详情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”\n\n"<annotation id="url">"了解详情"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"为了延长电池续航时间,省电模式会执行以下操作:\n\n• 开启深色主题\n• 关闭或限制后台活动、部分视觉效果和其他功能,例如“Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"为了减少流量消耗,流量节省程序会阻止某些应用在后台收发数据。您当前使用的应用可以收发数据,但频率可能会降低。举例而言,这可能意味着图片只有在您点按之后才会显示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要开启流量节省程序吗?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"开启"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 35bc1aa93b25..82b079fd98af 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為延長電池壽命,「省電模式」會:\n\n•開啟深色主題背景\n•關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"為延長電池壽命,「省電模式」會:\n\n•開啟深色主題背景\n•關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"為延長電池壽命,「省電模式」會:\n\n• 開啟深色主題背景\n• 關閉或限制背景活動、某些視覺效果和其他功能 (例如「Hey Google」)\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"為延長電池壽命,「省電模式」會:\n\n• 開啟深色主題背景\n• 停用或限制背景活動、部分視覺效果和其他功能 (例如「Hey Google」)"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。您正在使用的應用程式可存取資料,但次數可能會減少。例如,圖片可能需要輕按才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟「數據節省模式」嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6ccfc09a46a0..02c02008dea3 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"為了延長電池續航力,節約耗電量模式會執行以下動作:\n\n• 開啟深色主題\n• 關閉或限制背景活動、某些視覺效果和其他功能,例如「Ok Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"為了延長電池續航力,節約耗電量模式會執行以下動作:\n\n• 開啟深色主題\n• 關閉或限制背景活動、某些視覺效果和其他功能,例如「Ok Google」啟動字詞"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ff2baa6c7145..7fe333d4bc33 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"Ukuze unwebe impilo yebhethri, Isilondolozi Sebhethri:\n\n•Sivula itimu emnyama\n•Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"Ukuze unwebe impilo yebhethri, Isilondolozi sebhethri:\n\n•Sivula itimu emnyama\n•Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Ukuze unwebe impilo yebhethri, Isilondolozi Sebhethri:\n\n•Sivula itimu emnyama\n• Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”\n\n"<annotation id="url">"Funda kabanzi"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Ukuze unwebe impilo yebhethri, Isilondolozi sebhethri:\n\n•Sivula itimu emnyama\n• Sivala noma sibeka umkhawulo emsebenzini wangemuva, kweminye imithelela yokubuka, nakwezinye izici ezifana nokuthi “Ok Google”"</string>
<string name="data_saver_description" msgid="4995164271550590517">"Ukusiza ukwehlisa ukusetshenziswa kwedatha, iseva yedatha igwema ezinye izinhlelo zokusebenza ukuthi zithumele noma zamukele idatha ngasemuva. Uhlelo lokusebenza olisebenzisa okwamanje lingafinyelela idatha, kodwa lingenza kanjalo kancane. Lokhu kungachaza, isibonelo, ukuthi izithombe azibonisi uze uzithephe."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vula iseva yedatha?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Vula"</string>
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index 7f9d8749358c..6849a90f5010 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -15,14 +15,18 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bluetooth.tests" >
+ package="com.android.bluetooth.tests"
+ android:sharedUserId="android.uid.bluetooth" >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.permission.RECEIVE_SMS" />
+ <uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
index 4b32ceae0617..89dbe3f75b56 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
@@ -360,6 +360,30 @@ public class BluetoothStressTest extends InstrumentationTestCase {
mTestUtils.unpair(mAdapter, device);
}
+ /* Make sure there is at least 1 unread message in the last week on remote device */
+ public void testMceSetMessageStatus() {
+ int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations;
+ if (iterations == 0) {
+ return;
+ }
+
+ BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+ mTestUtils.enable(mAdapter);
+ mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null);
+ mTestUtils.mceGetUnreadMessage(mAdapter, device);
+
+ for (int i = 0; i < iterations; i++) {
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ);
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD);
+ }
+
+ /**
+ * It is hard to find device to support set undeleted status, so just
+ * set deleted in 1 iteration
+ **/
+ mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED);
+ }
+
private void sleep(long time) {
try {
Thread.sleep(time);
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
index 56e691d8c246..d19c2c3e7e24 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
@@ -40,6 +40,7 @@ import android.util.Log;
* [-e connect_input_iterations <iterations>] \
* [-e connect_pan_iterations <iterations>] \
* [-e start_stop_sco_iterations <iterations>] \
+ * [-e mce_set_message_status_iterations <iterations>] \
* [-e pair_address <address>] \
* [-e headset_address <address>] \
* [-e a2dp_address <address>] \
@@ -64,6 +65,7 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
public static int sConnectInputIterations = 100;
public static int sConnectPanIterations = 100;
public static int sStartStopScoIterations = 100;
+ public static int sMceSetMessageStatusIterations = 100;
public static String sDeviceAddress = "";
public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
@@ -173,6 +175,15 @@ public class BluetoothTestRunner extends InstrumentationTestRunner {
}
}
+ val = arguments.getString("mce_set_message_status_iterations");
+ if (val != null) {
+ try {
+ sMceSetMessageStatusIterations = Integer.parseInt(val);
+ } catch (NumberFormatException e) {
+ // Invalid argument, fall back to default value
+ }
+ }
+
val = arguments.getString("device_address");
if (val != null) {
sDeviceAddress = val;
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index ed613c36b89b..409025bc670d 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -56,6 +56,10 @@ public class BluetoothTestUtils extends Assert {
private static final int CONNECT_PROXY_TIMEOUT = 5000;
/** Time between polls in ms. */
private static final int POLL_TIME = 100;
+ /** Timeout to get map message in ms. */
+ private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000;
+ /** Timeout to set map message status in ms. */
+ private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000;
private abstract class FlagReceiver extends BroadcastReceiver {
private int mExpectedFlags = 0;
@@ -98,6 +102,8 @@ public class BluetoothTestUtils extends Assert {
private static final int STATE_TURNING_ON_FLAG = 1 << 6;
private static final int STATE_ON_FLAG = 1 << 7;
private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
+ private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9;
+ private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10;
public BluetoothReceiver(int expectedFlags) {
super(expectedFlags);
@@ -231,6 +237,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED;
+ break;
default:
mConnectionAction = null;
}
@@ -308,6 +317,34 @@ public class BluetoothTestUtils extends Assert {
}
}
+
+ private class MceSetMessageStatusReceiver extends FlagReceiver {
+ private static final int MESSAGE_RECEIVED_FLAG = 1;
+ private static final int STATUS_CHANGED_FLAG = 1 << 1;
+
+ public MceSetMessageStatusReceiver(int expectedFlags) {
+ super(expectedFlags);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
+ String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE);
+ assertNotNull(handle);
+ setFiredFlag(MESSAGE_RECEIVED_FLAG);
+ mMsgHandle = handle;
+ } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) {
+ int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
+ assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
+ setFiredFlag(STATUS_CHANGED_FLAG);
+ } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) {
+ int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
+ assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
+ setFiredFlag(STATUS_CHANGED_FLAG);
+ }
+ }
+ }
+
private BluetoothProfile.ServiceListener mServiceListener =
new BluetoothProfile.ServiceListener() {
@Override
@@ -326,6 +363,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mPan = (BluetoothPan) proxy;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mMce = (BluetoothMapClient) proxy;
+ break;
}
}
}
@@ -346,6 +386,9 @@ public class BluetoothTestUtils extends Assert {
case BluetoothProfile.PAN:
mPan = null;
break;
+ case BluetoothProfile.MAP_CLIENT:
+ mMce = null;
+ break;
}
}
}
@@ -362,6 +405,8 @@ public class BluetoothTestUtils extends Assert {
private BluetoothHeadset mHeadset = null;
private BluetoothHidHost mInput = null;
private BluetoothPan mPan = null;
+ private BluetoothMapClient mMce = null;
+ private String mMsgHandle = null;
/**
* Creates a utility instance for testing Bluetooth.
@@ -898,7 +943,7 @@ public class BluetoothTestUtils extends Assert {
* @param adapter The BT adapter.
* @param device The remote device.
* @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}.
+ * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}..
* @param methodName The method name to printed in the logs. If null, will be
* "connectProfile(profile=&lt;profile&gt;, device=&lt;device&gt;)"
*/
@@ -941,6 +986,8 @@ public class BluetoothTestUtils extends Assert {
assertTrue(((BluetoothHeadset)proxy).connect(device));
} else if (profile == BluetoothProfile.HID_HOST) {
assertTrue(((BluetoothHidHost)proxy).connect(device));
+ } else if (profile == BluetoothProfile.MAP_CLIENT) {
+ assertTrue(((BluetoothMapClient)proxy).connect(device));
}
break;
default:
@@ -1016,6 +1063,8 @@ public class BluetoothTestUtils extends Assert {
assertTrue(((BluetoothHeadset)proxy).disconnect(device));
} else if (profile == BluetoothProfile.HID_HOST) {
assertTrue(((BluetoothHidHost)proxy).disconnect(device));
+ } else if (profile == BluetoothProfile.MAP_CLIENT) {
+ assertTrue(((BluetoothMapClient)proxy).disconnect(device));
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
@@ -1373,6 +1422,89 @@ public class BluetoothTestUtils extends Assert {
}
}
+ public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) {
+ int mask;
+ String methodName = "getUnreadMessage";
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled", methodName));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired", methodName));
+ }
+
+ mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
+ assertNotNull(mMce);
+
+ if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
+ fail(String.format("%s device is not connected", methodName));
+ }
+
+ mMsgHandle = null;
+ mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG;
+ MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
+ assertTrue(mMce.getUnreadMessages(device));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) {
+ if ((receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("%s completed", methodName));
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask));
+ }
+
+ /**
+ * Set a message to read/unread/deleted/undeleted
+ */
+ public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) {
+ int mask;
+ String methodName = "setMessageStatus";
+
+ if (!adapter.isEnabled()) {
+ fail(String.format("%s bluetooth not enabled", methodName));
+ }
+
+ if (!adapter.getBondedDevices().contains(device)) {
+ fail(String.format("%s device not paired", methodName));
+ }
+
+ mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
+ assertNotNull(mMce);
+
+ if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
+ fail(String.format("%s device is not connected", methodName));
+ }
+
+ assertNotNull(mMsgHandle);
+ mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG;
+ MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
+
+ assertTrue(mMce.setMessageStatus(device, mMsgHandle, status));
+
+ long s = System.currentTimeMillis();
+ while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) {
+ if ((receiver.getFiredFlags() & mask) == mask) {
+ writeOutput(String.format("%s completed", methodName));
+ removeReceiver(receiver);
+ return;
+ }
+ sleep(POLL_TIME);
+ }
+
+ int firedFlags = receiver.getFiredFlags();
+ removeReceiver(receiver);
+ fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
+ methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask));
+ }
+
private void addReceiver(BroadcastReceiver receiver, String[] actions) {
IntentFilter filter = new IntentFilter();
for (String action: actions) {
@@ -1408,7 +1540,8 @@ public class BluetoothTestUtils extends Assert {
String[] actions = {
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED};
+ BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED,
+ BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED};
ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
expectedFlags);
addReceiver(receiver, actions);
@@ -1430,6 +1563,16 @@ public class BluetoothTestUtils extends Assert {
return receiver;
}
+ private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device,
+ int expectedFlags) {
+ String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED,
+ BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED,
+ BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED};
+ MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags);
+ addReceiver(receiver, actions);
+ return receiver;
+ }
+
private void removeReceiver(BroadcastReceiver receiver) {
mContext.unregisterReceiver(receiver);
mReceivers.remove(receiver);
@@ -1456,6 +1599,10 @@ public class BluetoothTestUtils extends Assert {
if (mPan != null) {
return mPan;
}
+ case BluetoothProfile.MAP_CLIENT:
+ if (mMce != null) {
+ return mMce;
+ }
break;
default:
return null;
@@ -1483,6 +1630,11 @@ public class BluetoothTestUtils extends Assert {
sleep(POLL_TIME);
}
return mPan;
+ case BluetoothProfile.MAP_CLIENT:
+ while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
+ sleep(POLL_TIME);
+ }
+ return mMce;
default:
return null;
}
diff --git a/core/tests/coretests/src/android/graphics/PaintNativeInstanceTest.kt b/core/tests/coretests/src/android/graphics/PaintNativeInstanceTest.kt
new file mode 100644
index 000000000000..ac88601a83f0
--- /dev/null
+++ b/core/tests/coretests/src/android/graphics/PaintNativeInstanceTest.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.Callable
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+
+// Verify that various calls to getNativeInstance do not deadlock or otherwise fail.
+@RunWith(AndroidJUnit4::class)
+class PaintNativeInstanceTest {
+
+ // Force a GC after each test, so that if there was a double free, it would happen now, rather
+ // than later during other tests.
+ @After
+ fun runGcAndFinalizersSync() {
+ Runtime.getRuntime().gc()
+ Runtime.getRuntime().runFinalization()
+ val fence = CountDownLatch(1)
+ object : Any() {
+ @Throws(Throwable::class)
+ protected fun finalize() = fence.countDown()
+ }
+ try {
+ do {
+ Runtime.getRuntime().gc()
+ Runtime.getRuntime().runFinalization()
+ } while (!fence.await(100, TimeUnit.MILLISECONDS))
+ } catch (ex: InterruptedException) {
+ throw RuntimeException(ex)
+ }
+ }
+
+ private fun setupComposeShader(test: (Paint, ComposeShader, Shader, Shader) -> Unit) {
+ val size = 255f
+ val blue = LinearGradient(0f, 0f, size, 0f, Color.GREEN, Color.BLUE,
+ Shader.TileMode.MIRROR)
+ val red = LinearGradient(0f, 0f, 0f, size, Color.GREEN, Color.RED,
+ Shader.TileMode.MIRROR)
+ val compose = ComposeShader(blue, red, BlendMode.SCREEN)
+ val paint = Paint().apply {
+ shader = compose
+ }
+ test(paint, compose, blue, red)
+ }
+
+ // Change the matrix arbitrarily to invalidate the shader.
+ private fun Shader.changeMatrix() {
+ val matrix = Matrix().apply {
+ setScale(2f, 2f)
+ }
+ setLocalMatrix(matrix)
+ }
+
+ @Test
+ fun testUnchangedPaintNativeInstance() = setupComposeShader {
+ paint, compose, shaderA, shaderB ->
+ val nativeInstance = paint.nativeInstance
+ for (shader in listOf(compose, shaderA, shaderB)) {
+ shader.changeMatrix()
+ // Although the shader is invalidated, the Paint's nativeInstance remains the same.
+ assertEquals(nativeInstance, paint.nativeInstance)
+ }
+ }
+
+ @Test
+ fun testInvalidateSubShader() = setupComposeShader {
+ paint, compose, shaderA, shaderB ->
+ // Trigger the creation of native objects.
+ shaderA.nativeInstance
+ compose.nativeInstance
+ val instanceB = shaderB.nativeInstance
+
+ // Changing shaderA's matrix invalidates shaderA and compose. A new instance will be lazily
+ // created for each of them. We cannot assert that the new nativeInstance does not match,
+ // since it might be allocated at the same location. But we can verify that shaderB did not
+ // change, and that there was no deadlock.
+ shaderA.changeMatrix()
+ assertEquals(instanceB, shaderB.nativeInstance)
+ paint.nativeInstance
+ }
+
+ @Test
+ fun testInvalidateSubShaderDraw() = setupComposeShader {
+ paint, _, _, shaderB ->
+
+ val original = PaintTask(paint).call()
+
+ // Change one of the subshaders and verify that the paint now draws differently.
+ shaderB.changeMatrix()
+ val changed = PaintTask(paint).call()
+ assertFalse(changed.sameAs(original))
+ }
+
+ /*
+ * This task will trigger the creation of native objects, if they have not already been
+ * created.
+ */
+ class PaintTask(private val mPaint: Paint) : Callable<Bitmap> {
+ private val size = 255 // matches size of gradients in setupComposeShader
+ override fun call(): Bitmap = Bitmap.createBitmap(size, size,
+ Bitmap.Config.ARGB_8888).apply {
+ val canvas = Canvas(this)
+ canvas.drawPaint(mPaint)
+ }
+ }
+
+ @Test
+ fun testMultiThreadShader() = setupComposeShader {
+ paint, _, _, _ ->
+ // Create an arbitrary number of tasks and try to start them at approximately the same time.
+ // They will race to create the native objects, but this should be safe.
+ val tasks = List(5) { PaintTask(paint) }
+ val results = Executors.newCachedThreadPool().invokeAll(tasks)
+ var expectedBitmap: Bitmap? = null
+ for (result in results) {
+ if (expectedBitmap == null) {
+ expectedBitmap = result.get()
+ } else {
+ assertTrue(expectedBitmap.sameAs(result.get()))
+ }
+ }
+ }
+
+ @Test
+ fun testMultiThreadColorFilter() {
+ val paint = Paint().apply {
+ color = Color.MAGENTA
+ colorFilter = LightingColorFilter(Color.BLUE, Color.GREEN)
+ }
+ // Create an arbitrary number of tasks and try to start them at approximately the same time.
+ // They will race to create the native objects, but this should be safe.
+ val tasks = List(5) { PaintTask(paint) }
+ val results = Executors.newCachedThreadPool().invokeAll(tasks)
+ for (result in results) {
+ assertEquals(Color.CYAN, result.get().getPixel(0, 0))
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
index d00d052db590..0af8c728aba3 100644
--- a/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
+++ b/core/tests/coretests/src/android/service/euicc/EuiccProfileInfoTest.java
@@ -154,6 +154,29 @@ public class EuiccProfileInfoTest {
}
@Test
+ public void testBuilder_BasedOnAnotherProfileWithEmptyAccessRules() {
+ EuiccProfileInfo p =
+ new EuiccProfileInfo.Builder("21430000000000006587")
+ .setNickname("profile nickname")
+ .setProfileName("profile name")
+ .setServiceProviderName("service provider")
+ .setCarrierIdentifier(
+ new CarrierIdentifier(
+ new byte[] {0x23, 0x45, 0x67},
+ "123",
+ "45"))
+ .setState(EuiccProfileInfo.PROFILE_STATE_ENABLED)
+ .setProfileClass(EuiccProfileInfo.PROFILE_CLASS_OPERATIONAL)
+ .setPolicyRules(EuiccProfileInfo.POLICY_RULE_DO_NOT_DELETE)
+ .setUiccAccessRule(null)
+ .build();
+
+ EuiccProfileInfo copied = new EuiccProfileInfo.Builder(p).build();
+
+ assertEquals(null, copied.getUiccAccessRules());
+ }
+
+ @Test
public void testEqualsHashCode() {
EuiccProfileInfo p =
new EuiccProfileInfo.Builder("21430000000000006587")
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index bfcf52af80bf..eb695258142a 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -86,7 +86,7 @@ public class ImeInsetsSourceConsumerTest {
false,
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
- SOFT_INPUT_ADJUST_RESIZE, 0);
+ SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mImeConsumer = (ImeInsetsSourceConsumer) mController.getSourceConsumer(ITYPE_IME);
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index c36f1067149e..801cd4ddb94e 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -165,7 +165,7 @@ public class InsetsControllerTest {
false,
new DisplayCutout(
Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
- SOFT_INPUT_ADJUST_RESIZE, 0);
+ SOFT_INPUT_ADJUST_RESIZE, 0, 0);
mController.onFrameChanged(new Rect(0, 0, 100, 100));
});
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 5260ef83cc4f..c7d835ca7c7e 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -29,6 +29,7 @@ import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -77,7 +78,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setVisible(true);
SparseIntArray typeSideMap = new SparseIntArray();
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, typeSideMap);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, typeSideMap);
assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
assertEquals(ISIDE_TOP, typeSideMap.get(ITYPE_STATUS_BAR));
@@ -96,7 +97,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, null);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null);
assertEquals(100, insets.getStableInsetBottom());
assertEquals(Insets.of(0, 0, 0, 100), insets.getInsetsIgnoringVisibility(Type.systemBars()));
assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
@@ -115,7 +116,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -131,7 +132,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, null);
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0, 0, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
assertEquals(100, insets.getInsets(ime()).bottom);
assertTrue(insets.isVisible(ime()));
@@ -147,11 +148,28 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 100, 300));
mState.getSource(ITYPE_IME).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING,
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
SYSTEM_UI_FLAG_LAYOUT_STABLE, null);
assertEquals(100, insets.getSystemWindowInsetTop());
insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING,
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
+ 0 /* legacySystemUiFlags */, null);
+ assertEquals(0, insets.getSystemWindowInsetTop());
+ }
+ }
+
+ @Test
+ public void testCalculateInsets_systemUiFlagLayoutStable_windowFlagFullscreen() {
+ try (final InsetsModeSession session =
+ new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
+ false, DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, FLAG_FULLSCREEN,
+ SYSTEM_UI_FLAG_LAYOUT_STABLE, null);
+ assertEquals(0, insets.getSystemWindowInsetTop());
+ insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_NOTHING, 0,
0 /* legacySystemUiFlags */, null);
assertEquals(0, insets.getSystemWindowInsetTop());
}
@@ -195,7 +213,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -211,7 +229,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false,
- false, DisplayCutout.NO_CUTOUT, 0, 0, null);
+ false, DisplayCutout.NO_CUTOUT, 0, 0, 0, null);
assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars()));
assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars()));
@@ -226,7 +244,7 @@ public class InsetsStateTest {
mState.getSource(ITYPE_IME).setVisible(true);
mState.removeSource(ITYPE_IME);
WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, false,
- DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, null);
+ DisplayCutout.NO_CUTOUT, SOFT_INPUT_ADJUST_RESIZE, 0, 0, null);
assertEquals(0, insets.getSystemWindowInsetBottom());
}
diff --git a/data/etc/preinstalled-packages-platform-overlays.xml b/data/etc/preinstalled-packages-platform-overlays.xml
index ecd7d40ff21d..84c1897a2b62 100644
--- a/data/etc/preinstalled-packages-platform-overlays.xml
+++ b/data/etc/preinstalled-packages-platform-overlays.xml
@@ -19,32 +19,250 @@
<config>
<install-in-user-type package="com.android.internal.display.cutout.emulation.corner">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.display.cutout.emulation.double">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.display.cutout.emulation.hole">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.display.cutout.emulation.tall">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.display.cutout.emulation.waterfall">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.twobutton">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.internal.systemui.navbar.threebutton">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.systemui.navbar.gestural">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.systemui.navbar.gestural_extra_wide_back">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.systemui.navbar.gestural_narrow_back">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
<install-in-user-type package="com.android.internal.systemui.navbar.gestural_wide_back">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
- <install-in-user-type package="com.android.internal.systemui.navbar.threebutton">
+ <install-in-user-type package="com.android.internal.systemui.onehanded.gestural">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
- <install-in-user-type package="com.android.internal.systemui.navbar.twobutton">
+ <install-in-user-type package="com.android.theme.color.amethyst">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
- <install-in-user-type package="com.android.internal.systemui.onehanded.gestural">
+ <install-in-user-type package="com.android.theme.color.aquamarine">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.black">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.carbon">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.cinnamon">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.green">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.ocean">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.orchid">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.palette">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.purple">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.sand">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.space">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.color.tangerine">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.font.notoserifsource">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.circular.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.circular.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.circular.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.circular.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.circular.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.filled.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.filled.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.filled.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.filled.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.filled.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.kai.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.kai.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.kai.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.kai.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.kai.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.rounded.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.rounded.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.rounded.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.rounded.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.rounded.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.sam.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.sam.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.sam.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.sam.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.sam.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.victor.android">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.victor.launcher">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.victor.settings">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.victor.systemui">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon_pack.victor.themepicker">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.pebble">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.roundedrect">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.squircle">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.taperedrect">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.teardrop">
+ <install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
+ </install-in-user-type>
+ <install-in-user-type package="com.android.theme.icon.vessel">
<install-in user-type="FULL" />
+ <install-in user-type="PROFILE" />
</install-in-user-type>
</config>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c710bed29361..6798c0a3f87e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -160,6 +160,7 @@ applications that come with the platform
<permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<permission name="android.permission.DUMP"/>
+ <permission name="android.permission.HANDLE_CAR_MODE_CHANGES"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_USERS"/>
@@ -198,6 +199,8 @@ applications that come with the platform
<permission name="android.permission.MANAGE_USERS" />
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
+ <permission name="android.permission.LOG_COMPAT_CHANGE" />
+ <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
</privapp-permissions>
<privapp-permissions package="com.android.providers.contacts">
@@ -426,6 +429,10 @@ applications that come with the platform
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<!-- Permissions required for CTS test - AdbManagerTest -->
<permission name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
+ <permission name="android.car.permission.CAR_DRIVING_STATE" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
+ <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/OWNERS b/data/keyboards/OWNERS
index 031a6c1c7a89..c4f6df824a39 100644
--- a/data/keyboards/OWNERS
+++ b/data/keyboards/OWNERS
@@ -2,3 +2,4 @@ set noparent
michaelwr@google.com
svv@google.com
+lzye@google.com
diff --git a/data/keyboards/Vendor_056e_Product_2010.kl b/data/keyboards/Vendor_056e_Product_2010.kl
new file mode 100644
index 000000000000..09e15eaa62b8
--- /dev/null
+++ b/data/keyboards/Vendor_056e_Product_2010.kl
@@ -0,0 +1,48 @@
+# 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.
+
+#
+# Elecom JC-U4113S in DirectInput Mode (D mode).
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 306 BUTTON_A
+key 307 BUTTON_B
+key 304 BUTTON_X
+key 305 BUTTON_Y
+
+key 308 BUTTON_L1
+key 309 BUTTON_R1
+key 310 BUTTON_L2
+key 311 BUTTON_R2
+
+key 312 BUTTON_THUMBL
+key 313 BUTTON_THUMBR
+
+key 314 BACK
+key 315 BUTTON_START
+
+# Left and right stick.
+axis 0x00 X
+axis 0x01 Y
+axis 0x05 Z
+axis 0x02 RZ
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# "Guide" button (Xbox key).
+key 316 BUTTON_MODE
diff --git a/data/keyboards/Vendor_056e_Product_2013.kl b/data/keyboards/Vendor_056e_Product_2013.kl
new file mode 100644
index 000000000000..c2a74a9fd442
--- /dev/null
+++ b/data/keyboards/Vendor_056e_Product_2013.kl
@@ -0,0 +1,44 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Elecom JC-U4113S in XInput Mode (X mode).
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+key 315 BUTTON_START
+key 314 BACK
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+axis 0x00 X
+axis 0x01 Y
+axis 0x03 Z
+axis 0x04 RZ
+
+axis 0x02 BRAKE
+axis 0x05 GAS
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# "Guide" button (Xbox key).
+key 316 BUTTON_MODE
diff --git a/data/keyboards/Vendor_1532_Product_0709.kl b/data/keyboards/Vendor_1532_Product_0709.kl
new file mode 100644
index 000000000000..20ea2ab7504e
--- /dev/null
+++ b/data/keyboards/Vendor_1532_Product_0709.kl
@@ -0,0 +1,51 @@
+# 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.
+
+#
+# Razer Junglecat Controller with wireless Bluetooth interface.
+#
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x133 BUTTON_X
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x134 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x02 Z
+axis 0x05 RZ
+
+# Left stick click
+key 0x13d BUTTON_THUMBL
+# Right stick click
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Select key
+key 0x13a BUTTON_SELECT
+# Start key
+key 0x13b BUTTON_START
diff --git a/data/keyboards/Vendor_27f8_Product_0bbf.kl b/data/keyboards/Vendor_27f8_Product_0bbf.kl
new file mode 100644
index 000000000000..a59f5663842c
--- /dev/null
+++ b/data/keyboards/Vendor_27f8_Product_0bbf.kl
@@ -0,0 +1,54 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Razer Kishi Mobile Controller
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x133 BUTTON_X
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x134 BUTTON_Y
+
+key 0x136 BUTTON_L1
+key 0x137 BUTTON_R1
+key 0x138 BUTTON_L2
+key 0x139 BUTTON_R2
+
+axis 0x00 X
+axis 0x01 Y
+
+axis 0x02 Z
+axis 0x05 RZ
+
+axis 0x09 RTRIGGER
+axis 0x0a LTRIGGER
+
+key 0x13d BUTTON_THUMBL
+key 0x13e BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Left Triangle Button
+key 0x13a BUTTON_SELECT
+# Right Triangle Button
+key 0x13b BUTTON_START
+# Home Button
+key 0x13c BUTTON_MODE
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java
index 4c2ef84404e2..8fd6f7f609c6 100644
--- a/graphics/java/android/graphics/ColorFilter.java
+++ b/graphics/java/android/graphics/ColorFilter.java
@@ -48,7 +48,7 @@ public class ColorFilter {
return 0;
}
- void discardNativeInstance() {
+ synchronized final void discardNativeInstance() {
if (mNativeInstance != 0) {
mCleaner.run();
mCleaner = null;
@@ -57,7 +57,7 @@ public class ColorFilter {
}
/** @hide */
- public long getNativeInstance() {
+ public synchronized final long getNativeInstance() {
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance();
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 279e2937a80a..b840f3f7654d 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -95,13 +95,9 @@ public class ComposeShader extends Shader {
/** @hide */
@Override
- protected void verifyNativeInstance() {
- if (mShaderA.getNativeInstance() != mNativeInstanceShaderA
- || mShaderB.getNativeInstance() != mNativeInstanceShaderB) {
- // Child shader native instance has been updated,
- // so our cached native instance is no longer valid - discard it
- discardNativeInstance();
- }
+ protected boolean shouldDiscardNativeInstance() {
+ return mShaderA.getNativeInstance() != mNativeInstanceShaderA
+ || mShaderB.getNativeInstance() != mNativeInstanceShaderB;
}
private static native long nativeCreate(long nativeMatrix,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 3b586242e5b1..28d7911c771f 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -674,10 +674,15 @@ public class Paint {
* Return the pointer to the native object while ensuring that any
* mutable objects that are attached to the paint are also up-to-date.
*
+ * Note: Although this method is |synchronized|, this is simply so it
+ * is not thread-hostile to multiple threads calling this method. It
+ * is still unsafe to attempt to change the Shader/ColorFilter while
+ * another thread attempts to access the native object.
+ *
* @hide
*/
@UnsupportedAppUsage
- public long getNativeInstance() {
+ public synchronized long getNativeInstance() {
long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
if (newNativeShader != mNativeShader) {
mNativeShader = newNativeShader;
diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java
index fb15d0794dd7..8154ebf1e508 100644
--- a/graphics/java/android/graphics/Shader.java
+++ b/graphics/java/android/graphics/Shader.java
@@ -150,7 +150,12 @@ public class Shader {
/**
* @hide Only to be used by subclasses in the graphics package.
*/
- protected final void discardNativeInstance() {
+ protected synchronized final void discardNativeInstance() {
+ discardNativeInstanceLocked();
+ }
+
+ // For calling inside a synchronized method.
+ private void discardNativeInstanceLocked() {
if (mNativeInstance != 0) {
mCleaner.run();
mCleaner = null;
@@ -159,11 +164,12 @@ public class Shader {
}
/**
- * Callback for subclasses to call {@link #discardNativeInstance()} if the most recently
- * constructed native instance is no longer valid.
+ * Callback for subclasses to specify whether the most recently
+ * constructed native instance is still valid.
* @hide Only to be used by subclasses in the graphics package.
*/
- protected void verifyNativeInstance() {
+ protected boolean shouldDiscardNativeInstance() {
+ return false;
}
@@ -171,9 +177,10 @@ public class Shader {
* @hide so it can be called by android.graphics.drawable but must not be called from outside
* the module.
*/
- public final long getNativeInstance() {
- // verify mNativeInstance is valid
- verifyNativeInstance();
+ public synchronized final long getNativeInstance() {
+ if (shouldDiscardNativeInstance()) {
+ discardNativeInstanceLocked();
+ }
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance(mLocalMatrix == null
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index b8934dc8c583..843b17703676 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -22,8 +22,4 @@ android_library {
"res",
],
manifest: "AndroidManifest.xml",
-
- platform_apis: true,
- sdk_version: "current",
- min_sdk_version: "system_current",
}
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml
index 257bf35c8e76..29d9b257cc59 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_focus_gain_animation.xml
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_gain_animation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:valueTo="1"
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml
index e032008b3750..70f553b89657 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_focus_loss_animation.xml
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_controls_focus_loss_animation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:valueTo="0"
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml
index 257bf35c8e76..29d9b257cc59 100644
--- a/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:valueTo="1"
diff --git a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml
index e032008b3750..70f553b89657 100644
--- a/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
+++ b/libs/WindowManager/Shell/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:valueTo="0"
diff --git a/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml
new file mode 100644
index 000000000000..8b3057d5841e
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="270"
+ android:startColor="#00000000"
+ android:endColor="#77000000"
+ android:type="linear" />
+</shape> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 000000000000..772d0a5ea89b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@android:color/transparent" />
+ <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml b/libs/WindowManager/Shell/res/drawable/pip_expand.xml
index 8f7fb1011cf4..c99d81934aab 100644
--- a/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_expand.xml
@@ -13,12 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<shape
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <gradient
- android:angle="270"
- android:startColor="#00000000"
- android:endColor="#77000000"
- android:type="linear" />
-</shape> \ No newline at end of file
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="36dp"
+ android:height="36dp"
+ android:viewportWidth="36"
+ android:viewportHeight="36">
+
+ <path
+ android:pathData="M0 0h36v36H0z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
+7v3h5v5h3V7h-8z" />
+</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml
new file mode 100644
index 000000000000..bcc850a854de
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_close_white.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
+ android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/pip_expand.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml
index cdb2ee50482f..56699dc04e10 100644
--- a/packages/SystemUI/res/drawable/pip_expand.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_fullscreen_white.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -15,15 +15,11 @@ Copyright (C) 2017 The Android Open Source Project
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="36dp"
- android:height="36dp"
- android:viewportWidth="36"
- android:viewportHeight="36">
-
- <path
- android:pathData="M0 0h36v36H0z" />
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
- android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
-7v3h5v5h3V7h-8z" />
-</vector> \ No newline at end of file
+ android:pathData="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_pause_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml
index 5b65f100490c..ef9b2d9c1c63 100644
--- a/packages/SystemUI/res/drawable/ic_pause_white.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_pause_white.xml
@@ -1,7 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
diff --git a/packages/SystemUI/res/drawable/ic_play_arrow_white.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml
index ddc9e8dd17a0..f12d2cbebc87 100644
--- a/packages/SystemUI/res/drawable/ic_play_arrow_white.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_play_arrow_white.xml
@@ -1,7 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2016 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml
new file mode 100644
index 000000000000..b61e98ce2f9f
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/pip_ic_settings.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/pip_icon.xml b/libs/WindowManager/Shell/res/drawable/pip_icon.xml
index bd92ccd2e6e3..b19d907d1ff3 100644
--- a/packages/SystemUI/res/drawable/pip_icon.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_icon.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2017 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
diff --git a/packages/SystemUI/res/drawable/pip_resize_handle.xml b/libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml
index 0a8cbc429dd8..4d1e080cf466 100644
--- a/packages/SystemUI/res/drawable/pip_resize_handle.xml
+++ b/libs/WindowManager/Shell/res/drawable/pip_resize_handle.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-Copyright (C) 2020 The Android Open Source Project
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
diff --git a/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml b/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml
new file mode 100644
index 000000000000..cce13035dba7
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/tv_pip_button_focused.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/libs/WindowManager/Shell/res/layout/pip_menu_action.xml b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml
new file mode 100644
index 000000000000..7a026ca63f50
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/pip_menu_action.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<ImageButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/pip_action_size"
+ android:layout_height="@dimen/pip_action_size"
+ android:padding="@dimen/pip_action_padding"
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:forceHasOverlappingRendering="false" />
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
index 2b33e17a5fbd..18064b547d4d 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/libs/WindowManager/Shell/res/layout/pip_menu_activity.xml
@@ -1,17 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+ Copyright (C) 2020 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
@@ -68,7 +69,7 @@
android:layout_gravity="top|start"
android:padding="@dimen/pip_action_padding"
android:contentDescription="@string/pip_phone_settings"
- android:src="@drawable/ic_settings"
+ android:src="@drawable/pip_ic_settings"
android:background="?android:selectableItemBackgroundBorderless" />
<ImageButton
@@ -78,7 +79,7 @@
android:layout_gravity="top|end"
android:padding="@dimen/pip_action_padding"
android:contentDescription="@string/pip_phone_close"
- android:src="@drawable/ic_close_white"
+ android:src="@drawable/pip_ic_close_white"
android:background="?android:selectableItemBackgroundBorderless" />
<!--TODO (b/156917828): Add content description for a11y purposes?-->
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
index b9b0154e70b7..72287c144bed 100644
--- a/packages/SystemUI/res/layout/tv_pip_control_button.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_control_button.xml
@@ -1,22 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
+ 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.systemui.pip.tv.PipControlButtonView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
index 0b7bce13d761..22e0452d620d 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml
@@ -1,22 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
+ 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.systemui.pip.tv.PipControlsView}. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
@@ -24,7 +21,7 @@
android:id="@+id/full_button"
android:layout_width="@dimen/picture_in_picture_button_width"
android:layout_height="wrap_content"
- android:src="@drawable/ic_fullscreen_white_24dp"
+ android:src="@drawable/pip_ic_fullscreen_white"
android:text="@string/pip_fullscreen" />
<com.android.systemui.pip.tv.PipControlButtonView
@@ -32,7 +29,7 @@
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/ic_close_white"
+ android:src="@drawable/pip_ic_close_white"
android:text="@string/pip_close" />
<com.android.systemui.pip.tv.PipControlButtonView
@@ -40,7 +37,7 @@
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/ic_pause_white"
+ android:src="@drawable/pip_ic_pause_white"
android:text="@string/pip_pause"
android:visibility="gone" />
</merge>
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
new file mode 100644
index 000000000000..e6cd1122ca77
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_custom_control.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.systemui.pip.tv.PipControlButtonView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/picture_in_picture_button_width"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" />
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
new file mode 100644
index 000000000000..a049787b40b9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android: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.systemui.pip.tv.PipControlsView
+ android:id="@+id/pip_controls"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:alpha="0" />
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
new file mode 100644
index 000000000000..7920fd237a08
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<resources>
+ <!-- The dimensions to user for picture-in-picture action buttons. -->
+ <dimen name="picture_in_picture_button_width">100dp</dimen>
+ <dimen name="picture_in_picture_button_start_margin">-50dp</dimen>
+</resources>
+
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index c894eb0133b5..245c0725c2a8 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -1,21 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/*
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
<resources>
-</resources> \ No newline at end of file
+ <!-- Animation duration for resizing of PIP when entering/exiting. -->
+ <integer name="config_pipResizeAnimationDuration">425</integer>
+
+ <!-- Allow dragging the PIP to a location to close it -->
+ <bool name="config_pipEnableDismissDragToEdge">true</bool>
+
+ <!-- Allow PIP to resize to a slightly bigger state upon touch/showing the menu -->
+ <bool name="config_pipEnableResizeForMenu">true</bool>
+
+ <!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
+ <bool name="config_pipEnableRoundCorner">false</bool>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
new file mode 100644
index 000000000000..48c3cad596f1
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -0,0 +1,58 @@
+<?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.
+-->
+<resources>
+ <dimen name="dismiss_circle_size">52dp</dimen>
+
+ <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
+ <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+
+ <!-- The padding around a PiP actions. -->
+ <dimen name="pip_action_padding">12dp</dimen>
+
+ <!-- The height of the PiP actions container in which the actions are vertically centered. -->
+ <dimen name="pip_action_size">48dp</dimen>
+
+ <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
+ the configuration of the device, so we can't use -land resources. -->
+ <dimen name="pip_between_action_padding_land">8dp</dimen>
+
+ <!-- The buffer to use when calculating whether the pip is in an adjust zone. -->
+ <dimen name="pip_bottom_offset_buffer">1dp</dimen>
+
+ <!-- The corner radius for PiP window. -->
+ <dimen name="pip_corner_radius">8dp</dimen>
+
+ <!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
+ <dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
+
+ <!-- The bottom margin of the expand container when there are actions.
+ Equal to pip_action_size - pip_action_padding. -->
+ <dimen name="pip_expand_container_edge_margin">30dp</dimen>
+
+ <!-- The shortest-edge size of the expanded PiP. -->
+ <dimen name="pip_expanded_shortest_edge_size">160dp</dimen>
+
+ <!-- The additional offset to apply to the IME animation to account for the input field. -->
+ <dimen name="pip_ime_offset">48dp</dimen>
+
+ <!-- The touchable/draggable edge size for PIP resize. -->
+ <dimen name="pip_resize_edge_size">48dp</dimen>
+
+ <!-- PIP Resize handle size and margin. -->
+ <dimen name="pip_resize_handle_size">12dp</dimen>
+ <dimen name="pip_resize_handle_margin">4dp</dimen>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/ids.xml b/libs/WindowManager/Shell/res/values/ids.xml
new file mode 100644
index 000000000000..ed20398f309d
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/ids.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <item type="id" name="action_pip_resize" />
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
new file mode 100644
index 000000000000..6752b56fcdf3
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -0,0 +1,56 @@
+<?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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for PIP close button [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_close">Close</string>
+
+ <!-- Making the PIP fullscreen [CHAR LIMIT=25] -->
+ <string name="pip_phone_expand">Expand</string>
+
+ <!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_settings">Settings</string>
+
+ <!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
+ <string name="pip_menu_title">Menu</string>
+
+ <!-- PiP BTW notification title. [CHAR LIMIT=50] -->
+ <string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
+
+ <!-- PiP BTW notification description. [CHAR LIMIT=NONE] -->
+ <string name="pip_notification_message">If you don\'t want <xliff:g id="name" example="Google Maps">%s</xliff:g> to use this feature, tap to open settings and turn it off.</string>
+
+ <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_play">Play</string>
+
+ <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_pause">Pause</string>
+
+ <!-- Button to skip to the next media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_skip_to_next">Skip to next</string>
+
+ <!-- Button to skip to the prev media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
+ <string name="pip_skip_to_prev">Skip to previous</string>
+
+ <!-- Accessibility action for resizing PIP [CHAR LIMIT=NONE] -->
+ <string name="accessibility_action_pip_resize">Resize</string>
+
+ <!-- TODO Deprecated. Label for PIP action to Minimize the PIP. DO NOT TRANSLATE [CHAR LIMIT=25] -->
+ <string name="pip_phone_minimize">Minimize</string>
+
+ <!-- TODO Deprecated. Label for PIP the drag to dismiss hint. DO NOT TRANSLATE [CHAR LIMIT=NONE]-->
+ <string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
+</resources>
diff --git a/libs/WindowManager/Shell/res/values/strings_tv.xml b/libs/WindowManager/Shell/res/values/strings_tv.xml
new file mode 100644
index 000000000000..2dfdcabaa931
--- /dev/null
+++ b/libs/WindowManager/Shell/res/values/strings_tv.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Picture-in-Picture (PIP) notification -->
+ <!-- Title for the notification channel for TV PIP controls. [CHAR LIMIT=NONE] -->
+ <string name="notification_channel_tv_pip">Picture-in-Picture</string>
+
+ <!-- Title of the picture-in-picture (PIP) notification title
+ when the media doesn't have title [CHAR LIMIT=NONE] -->
+ <string name="pip_notification_unknown_title">(No title program)</string>
+
+ <!-- Picture-in-Picture (PIP) menu -->
+ <eat-comment />
+ <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
+ <string name="pip_close">Close PIP</string>
+
+ <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
+ <string name="pip_fullscreen">Full screen</string>
+</resources>
+
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5a50245a3765..67d8c07e61de 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -149,6 +149,9 @@ void DeferredLayerUpdater::apply() {
sk_sp<SkImage> layerImage = mImageSlots[slot].createIfNeeded(
hardwareBuffer, dataspace, newContent,
mRenderState.getRenderThread().getGrContext());
+ // unref to match the ref added by ASurfaceTexture_dequeueBuffer. eglCreateImageKHR
+ // (invoked by createIfNeeded) will add a ref to the AHardwareBuffer.
+ AHardwareBuffer_release(hardwareBuffer);
if (layerImage.get()) {
SkMatrix textureTransform;
mat4(transformMatrix).copyTo(textureTransform);
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index 6a12a203b9f8..a6137b073d5a 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -125,22 +125,22 @@ const std::vector<minikin::FontVariation>& MinikinFontSkia::GetAxes() const {
std::shared_ptr<minikin::MinikinFont> MinikinFontSkia::createFontWithVariation(
const std::vector<minikin::FontVariation>& variations) const {
- SkFontArguments params;
+ SkFontArguments args;
int ttcIndex;
std::unique_ptr<SkStreamAsset> stream(mTypeface->openStream(&ttcIndex));
LOG_ALWAYS_FATAL_IF(stream == nullptr, "openStream failed");
- params.setCollectionIndex(ttcIndex);
- std::vector<SkFontArguments::Axis> skAxes;
- skAxes.resize(variations.size());
+ args.setCollectionIndex(ttcIndex);
+ std::vector<SkFontArguments::VariationPosition::Coordinate> skVariation;
+ skVariation.resize(variations.size());
for (size_t i = 0; i < variations.size(); i++) {
- skAxes[i].fTag = variations[i].axisTag;
- skAxes[i].fStyleValue = SkFloatToScalar(variations[i].value);
+ skVariation[i].axis = variations[i].axisTag;
+ skVariation[i].value = SkFloatToScalar(variations[i].value);
}
- params.setAxes(skAxes.data(), skAxes.size());
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), args));
return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, mFilePath,
ttcIndex, variations);
diff --git a/libs/hwui/jni/FontFamily.cpp b/libs/hwui/jni/FontFamily.cpp
index a2fef1e19328..68eaa0a3ca54 100644
--- a/libs/hwui/jni/FontFamily.cpp
+++ b/libs/hwui/jni/FontFamily.cpp
@@ -104,21 +104,21 @@ static jlong FontFamily_getFamilyReleaseFunc(CRITICAL_JNI_PARAMS) {
static bool addSkTypeface(NativeFamilyBuilder* builder, sk_sp<SkData>&& data, int ttcIndex,
jint weight, jint italic) {
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
for (const auto& axis : builder->axes) {
- skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
+ skVariation.push_back({axis.axisTag, axis.value});
}
const size_t fontSize = data->size();
const void* fontPtr = data->data();
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
- SkFontArguments params;
- params.setCollectionIndex(ttcIndex);
- params.setAxes(skiaAxes.data(), skiaAxes.size());
+ SkFontArguments args;
+ args.setCollectionIndex(ttcIndex);
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
if (face == NULL) {
ALOGE("addFont failed to create font, invalid request");
builder->axes.clear();
diff --git a/libs/hwui/jni/fonts/Font.cpp b/libs/hwui/jni/fonts/Font.cpp
index 5714cd1d0390..996cdceed8a7 100644
--- a/libs/hwui/jni/fonts/Font.cpp
+++ b/libs/hwui/jni/fonts/Font.cpp
@@ -93,19 +93,19 @@ static jlong Font_Builder_build(JNIEnv* env, jobject clazz, jlong builderPtr, jo
sk_sp<SkData> data(SkData::MakeWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
- FatVector<SkFontArguments::Axis, 2> skiaAxes;
+ FatVector<SkFontArguments::VariationPosition::Coordinate, 2> skVariation;
for (const auto& axis : builder->axes) {
- skiaAxes.emplace_back(SkFontArguments::Axis{axis.axisTag, axis.value});
+ skVariation.push_back({axis.axisTag, axis.value});
}
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(std::move(data)));
- SkFontArguments params;
- params.setCollectionIndex(ttcIndex);
- params.setAxes(skiaAxes.data(), skiaAxes.size());
+ SkFontArguments args;
+ args.setCollectionIndex(ttcIndex);
+ args.setVariationDesignPosition({skVariation.data(), static_cast<int>(skVariation.size())});
sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
- sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), params));
+ sk_sp<SkTypeface> face(fm->makeFromStream(std::move(fontData), args));
if (face == nullptr) {
jniThrowException(env, "java/lang/IllegalArgumentException",
"Failed to create internal object. maybe invalid font data.");
diff --git a/location/java/android/location/package.html b/location/java/android/location/package.html
index 2355e725b6c5..20c5c54d6921 100644
--- a/location/java/android/location/package.html
+++ b/location/java/android/location/package.html
@@ -6,7 +6,7 @@
<p class="warning">
<strong>This API is not the recommended method for accessing Android location.</strong><br>
The
-<a href="{@docRoot}reference/com/google/android/gms/location/package-summary.html">Google Location Services API</a>,
+<a href="https://developers.google.com/android/reference/com/google/android/gms/location/package-summary">Google Location Services API</a>,
part of Google Play services, is the preferred way to add location-awareness to
your app. It offers a simpler API, higher accuracy, low-power geofencing, and
more. If you are currently using the android.location API, you are strongly
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 403a7667c150..0822cda04417 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -611,24 +611,18 @@ public class GnssMetrics {
if (atomTag != FrameworkStatsLog.GNSS_STATS) {
throw new UnsupportedOperationException("Unknown tagId = " + atomTag);
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mLocationFailureReportsStatistics.getCount())
- .writeLong(mLocationFailureReportsStatistics.getLongSum())
- .writeLong(mTimeToFirstFixMilliSReportsStatistics.getCount())
- .writeLong(mTimeToFirstFixMilliSReportsStatistics.getLongSum())
- .writeLong(mPositionAccuracyMetersReportsStatistics.getCount())
- .writeLong(mPositionAccuracyMetersReportsStatistics.getLongSum())
- .writeLong(mTopFourAverageCn0DbmHzReportsStatistics.getCount())
- .writeLong(mTopFourAverageCn0DbmHzReportsStatistics.getLongSum())
- .writeLong(mL5TopFourAverageCn0DbmHzReportsStatistics.getCount())
- .writeLong(mL5TopFourAverageCn0DbmHzReportsStatistics.getLongSum())
- .writeLong(mSvStatusReports)
- .writeLong(mSvStatusReportsUsedInFix)
- .writeLong(mL5SvStatusReports)
- .writeLong(mL5SvStatusReportsUsedInFix)
- .build();
- data.add(e);
+ data.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ mLocationFailureReportsStatistics.getCount(),
+ mLocationFailureReportsStatistics.getLongSum(),
+ mTimeToFirstFixMilliSReportsStatistics.getCount(),
+ mTimeToFirstFixMilliSReportsStatistics.getLongSum(),
+ mPositionAccuracyMetersReportsStatistics.getCount(),
+ mPositionAccuracyMetersReportsStatistics.getLongSum(),
+ mTopFourAverageCn0DbmHzReportsStatistics.getCount(),
+ mTopFourAverageCn0DbmHzReportsStatistics.getLongSum(),
+ mL5TopFourAverageCn0DbmHzReportsStatistics.getCount(),
+ mL5TopFourAverageCn0DbmHzReportsStatistics.getLongSum(), mSvStatusReports,
+ mSvStatusReportsUsedInFix, mL5SvStatusReports, mL5SvStatusReportsUsedInFix));
return StatsManager.PULL_SUCCESS;
}
}
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 590def4d4ced..98ca2f9c4253 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -34,7 +34,6 @@ import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Bundle;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IHwBinder;
import android.os.Looper;
@@ -50,6 +49,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -392,7 +392,10 @@ public final class MediaCas implements AutoCloseable {
@Override
public void onReclaimResources() {
synchronized (mSessionMap) {
- mSessionMap.forEach((casSession, sessionResourceHandle) -> casSession.close());
+ List<Session> sessionList = new ArrayList<>(mSessionMap.keySet());
+ for (Session casSession: sessionList) {
+ casSession.close();
+ }
}
mEventHandler.sendMessage(mEventHandler.obtainMessage(
EventHandler.MSG_CAS_RESOURCE_LOST));
@@ -734,7 +737,7 @@ public final class MediaCas implements AutoCloseable {
ResourceClientProfile profile =
new ResourceClientProfile(tvInputServiceSessionId, priorityHint);
mTunerResourceManager.registerClientProfile(
- profile, new HandlerExecutor(mEventHandler), mResourceListener, clientId);
+ profile, context.getMainExecutor(), mResourceListener, clientId);
mClientId = clientId[0];
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index ebd7658381ee..942f90896eb0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -167,34 +167,6 @@ public class CameraBinderTest extends AndroidTestCase {
}
}
- @SmallTest
- public void testConnectLegacy() throws Exception {
- final int CAMERA_HAL_API_VERSION_1_0 = 0x100;
- for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
- ICamera cameraUser = null;
- ICameraClient dummyCallbacks = new DummyCameraClient();
-
- String clientPackageName = getContext().getPackageName();
-
- try {
- cameraUser = mUtils.getCameraService()
- .connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
- clientPackageName,
- ICameraService.USE_CALLING_UID);
- assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
-
- Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
- } catch (RuntimeException e) {
- // Not all camera device support openLegacy.
- Log.i(TAG, "Unable to open camera as HAL1 legacy camera device " + e);
- } finally {
- if (cameraUser != null) {
- cameraUser.disconnect();
- }
- }
- }
- }
-
static class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
/*
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java
deleted file mode 100644
index 14bbe44c1516..000000000000
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraOpenTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.mediaframeworktest.unit;
-
-import android.hardware.Camera;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-/**
- * <pre>
- * adb shell am instrument \
- * -e class 'com.android.mediaframeworktest.unit.CameraOpenTest' \
- * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- * </pre>
- */
-public class CameraOpenTest extends junit.framework.TestCase {
- private static String TAG = "CameraOpenTest";
-
- private Camera mCamera;
-
- /**
- * Test @hide android.hardware.Camera#openLegacy API that cannot be tested in CTS.
- */
- @SmallTest
- public void testOpenLegacy() {
- int nCameras = Camera.getNumberOfCameras();
- for (int id = 0; id < nCameras; id++) {
- try {
- mCamera.openLegacy(id, Camera.CAMERA_HAL_API_VERSION_1_0);
- } catch (RuntimeException e) {
- Log.i(TAG, "Unable to open camera as HAL1 legacy camera device " + e);
- } finally {
- if (mCamera != null) {
- mCamera.release();
- }
- }
- }
- }
-}
diff --git a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
index de5ed5422dd1..5c87d30068b2 100644
--- a/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
+++ b/media/tests/MediaTranscodingTest/src/com/android/mediatranscodingtest/MediaTranscodingBenchmark.java
@@ -283,5 +283,50 @@ public class MediaTranscodingBenchmark
String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
transcode(testVideoName, transcodedVideoName);
- }*/
+ } */
+
+ @Test
+ public void testBenchmarkingHEVCToAVCWith107FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_107frame_hevc_4Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+
+ @Test
+ public void testBenchmarkingHEVCToAVCWith928FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_928frame_hevc_4Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+
+ @Test
+ public void testBenchmarkingHEVCToAVCWith1863FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_1863frame_hevc_4Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+
+ @Test
+ public void testBenchmarkingHEVCToAVCWith3863FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_3863frame_hevc_4Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
+
+ @Test
+ public void testBenchmarkingHEVCToAVCWith9374FramesWithoutAudio() throws Exception {
+ String videoNameWithoutExtension = "video_1920x1080_9374frame_hevc_4Mbps_30fps";
+ String testVideoName = videoNameWithoutExtension + ".mp4";
+ String transcodedVideoName = videoNameWithoutExtension + "_transcode.mp4";
+
+ transcode(testVideoName, transcodedVideoName);
+ }
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index fe431e226606..c14f23f6ace0 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -47256,6 +47256,7 @@ package android.telephony.ims.feature {
}
public static class MmTelFeature.MmTelCapabilities {
+ method public final boolean isCapable(int);
field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8
field public static final int CAPABILITY_TYPE_UT = 4; // 0x4
field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index c8406f199edd..a5ca196ef5b4 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -1,4 +1,12 @@
// Signature format: 2.0
+package android.app {
+
+ public class AppOpsManager {
+ field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
+ }
+
+}
+
package android.content.rollback {
public class RollbackManagerFrameworkInitializer {
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index b693b0ef0664..b41ab93295b5 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -11118,7 +11118,6 @@ package android.telephony.ims.feature {
ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
ctor public MmTelFeature.MmTelCapabilities(int);
method public final void addCapabilities(int);
- method public final boolean isCapable(int);
method public final void removeCapabilities(int);
}
diff --git a/packages/CarSystemUI/TEST_MAPPING b/packages/CarSystemUI/TEST_MAPPING
index f520c8a07a16..54afb9097f87 100644
--- a/packages/CarSystemUI/TEST_MAPPING
+++ b/packages/CarSystemUI/TEST_MAPPING
@@ -18,5 +18,15 @@
}
]
}
+ ],
+ "carsysui-presubmit": [
+ {
+ "name": "CarSystemUITests",
+ "options" : [
+ {
+ "include-annotation": "com.android.systemui.car.CarSystemUiTest"
+ }
+ ]
+ }
]
}
diff --git a/packages/CarSystemUI/res/layout/system_icons.xml b/packages/CarSystemUI/res/layout/system_icons.xml
index a7dd65eab550..d23579294ce8 100644
--- a/packages/CarSystemUI/res/layout/system_icons.xml
+++ b/packages/CarSystemUI/res/layout/system_icons.xml
@@ -31,10 +31,4 @@
android:gravity="center_vertical"
android:orientation="horizontal"
/>
-
- <com.android.systemui.BatteryMeterView
- android:id="@+id/battery"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- />
</LinearLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.java
new file mode 100644
index 000000000000..5f593b06c511
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarSystemUiTest.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.systemui.car;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates that a test class should be run as part of CarSystemUI presubmit
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface CarSystemUiTest {
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 37dfce4e16ce..35b2080dddf9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,10 +16,12 @@
package com.android.systemui.car.navigationbar;
+import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -368,13 +370,15 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
- WindowManager.LayoutParams.TYPE_STATUS_BAR,
+ WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("TopCarNavigationBar");
+ lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
+ lp.setFitInsetsTypes(0);
lp.windowAnimations = 0;
lp.gravity = Gravity.TOP;
mWindowManager.addView(mTopNavigationBarWindow, lp);
@@ -388,13 +392,14 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
PixelFormat.TRANSLUCENT);
lp.setTitle("BottomCarNavigationBar");
+ lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
lp.windowAnimations = 0;
lp.gravity = Gravity.BOTTOM;
mWindowManager.addView(mBottomNavigationBarWindow, lp);
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 029d4c7fa2fb..0ced4021ce38 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,7 +16,10 @@
package com.android.systemui.car.navigationbar;
+import static android.view.WindowInsets.Type.systemBars;
+
import android.content.Context;
+import android.graphics.Insets;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
@@ -79,9 +82,28 @@ public class CarNavigationBarView extends LinearLayout {
@Override
public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
+ applyMargins(windowInsets.getInsets(systemBars()));
return windowInsets;
}
+ private void applyMargins(Insets insets) {
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getLayoutParams() instanceof LayoutParams) {
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
+ || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
+ lp.rightMargin = insets.right;
+ lp.leftMargin = insets.left;
+ lp.topMargin = insets.top;
+ lp.bottomMargin = insets.bottom;
+ child.requestLayout();
+ }
+ }
+ }
+ }
+
// Used to forward touch events even if the touch was initiated from a child component
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
index bab67154e75d..0a677bfaa742 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/CarStatusBarHeader.java
@@ -26,7 +26,6 @@ import android.widget.LinearLayout;
import androidx.annotation.IdRes;
import com.android.settingslib.Utils;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
import com.android.systemui.plugins.DarkIconDispatcher;
@@ -49,10 +48,7 @@ public class CarStatusBarHeader extends LinearLayout {
float intensity = colorForeground == Color.WHITE ? 0f : 1f;
Rect tintArea = new Rect(0, 0, 0, 0);
- applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
-
- ((BatteryMeterView) findViewById(R.id.battery)).setForceShowPercent(true);
}
private void applyDarkness(@IdRes int id, Rect tintArea, float intensity, int color) {
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index fe59cbf20a13..d769cacadf1d 100644
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -33,6 +33,7 @@ import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter;
import com.android.systemui.SysuiBaseFragmentTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -55,6 +56,7 @@ import java.util.Collections;
* test suite causes errors, such as the incorrect settings provider being cached.
* For an example, see {@link com.android.systemui.DependencyTest}.
*/
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase {
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
index 7996170ba7d6..e179ef1ce2a4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/hvac/HvacControllerTest.java
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -39,6 +40,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 189e240169c3..62dc23624520 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -41,6 +41,7 @@ import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -59,6 +60,7 @@ import org.mockito.MockitoAnnotations;
import dagger.Lazy;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
index a57736bb3502..4b8268052324 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
index 893057e222a9..f623c26d12b6 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonSelectionStateControllerTest.java
@@ -28,6 +28,7 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index e84e42c77245..dec8b8ecdfb4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -31,6 +31,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.hvac.HvacController;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -41,6 +42,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index 0caa86f0eab2..d9edfa960858 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -45,6 +45,7 @@ import com.android.internal.view.AppearanceRegion;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -63,6 +64,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
index 19e394f69af4..47fd8201d197 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarViewTest.java
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.After;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
index bcaa5e9a03ee..173f5487c728 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
@@ -37,6 +37,7 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.tests.R;
@@ -45,6 +46,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
index ccaeb458fe54..384888ab42c3 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
@@ -38,6 +39,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
index 89dac58cd2a7..d51aeb18135d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/NotificationVisibilityLoggerTest.java
@@ -37,6 +37,7 @@ import com.android.car.notification.NotificationDataManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -49,6 +50,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Collections;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
index 77620f3fb345..421e2109356d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppDetectorTest.java
@@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -44,6 +45,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
index 73f9f6a55afc..20576e9ec11f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/sideloaded/SideLoadedAppListenerTest.java
@@ -35,6 +35,7 @@ import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
index 797dbf515b7e..2e9d43b595a1 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewControllerTest.java
@@ -36,6 +36,7 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.window.OverlayViewGlobalStateController;
import org.junit.Before;
@@ -44,6 +45,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
index a808e2d40e26..de6feb64391f 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/userswitcher/UserSwitchTransitionViewMediatorTest.java
@@ -25,6 +25,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import com.android.systemui.car.CarServiceProvider;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +33,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index 232df2eced39..31f1170c9603 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -35,11 +35,13 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
index 45a05ac69bd7..7311cdb68a3c 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java
@@ -39,6 +39,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.car.CarDeviceProvisionedController;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.tests.R;
@@ -52,6 +53,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
index c24a3b52e348..e784761f6d5d 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewControllerTest.java
@@ -29,6 +29,7 @@ import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -39,6 +40,7 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index cba42e5a9be4..20f9bc8ec1cb 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -32,6 +32,7 @@ import android.view.ViewStub;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import com.android.systemui.tests.R;
@@ -44,6 +45,7 @@ import org.mockito.MockitoAnnotations;
import java.util.Arrays;
+@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index 9420954748c4..75bd32ec0301 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -20,6 +20,7 @@ android_app {
certificate: "platform",
privileged: true,
platform_apis: true,
+ rename_resources_package: false,
static_libs: [
"xz-java",
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
index 9535ef06f888..348c971e17cc 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/hp/ServiceListener.java
@@ -22,6 +22,8 @@ import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.text.TextUtils;
+import androidx.annotation.GuardedBy;
+
import com.android.printservice.recommendation.R;
import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
import com.android.printservice.recommendation.util.PrinterHashMap;
@@ -40,7 +42,12 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
private final String[] mServiceType;
private final Observer mObserver;
private final ServiceResolveQueue mResolveQueue;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
+
+ @GuardedBy("mLock")
public HashMap<String, PrinterHashMap> mVendorHashMap = new HashMap<>();
public interface Observer {
@@ -73,108 +80,120 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
printerFound(nsdServiceInfo);
}
- private synchronized void printerFound(NsdServiceInfo nsdServiceInfo) {
+ private void printerFound(NsdServiceInfo nsdServiceInfo) {
if (nsdServiceInfo == null) return;
if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
String vendor = MDnsUtils.getVendor(nsdServiceInfo);
if (vendor == null) vendor = "";
- for(Map.Entry<String,VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
- for(String vendorValues : entry.getValue().mDNSValues) {
- if (vendor.equalsIgnoreCase(vendorValues)) {
+
+ boolean mapsChanged;
+ synchronized (mLock) {
+ for (Map.Entry<String, VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
+ for (String vendorValues : entry.getValue().mDNSValues) {
+ if (vendor.equalsIgnoreCase(vendorValues)) {
+ vendor = entry.getValue().mVendorID;
+ break;
+ }
+ }
+ // intentional pointer check
+ //noinspection StringEquality
+ if ((vendor != entry.getValue().mVendorID) &&
+ MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
vendor = entry.getValue().mVendorID;
- break;
}
+ // intentional pointer check
+ //noinspection StringEquality
+ if (vendor == entry.getValue().mVendorID) break;
}
- // intentional pointer check
- //noinspection StringEquality
- if ((vendor != entry.getValue().mVendorID) &&
- MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
- vendor = entry.getValue().mVendorID;
- }
- // intentional pointer check
- //noinspection StringEquality
- if (vendor == entry.getValue().mVendorID) break;
- }
- if (TextUtils.isEmpty(vendor)) {
- return;
- }
+ if (TextUtils.isEmpty(vendor)) {
+ return;
+ }
- if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
- return;
- boolean mapsChanged;
+ if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
+ return;
- PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
- if (vendorHash == null) {
- vendorHash = new PrinterHashMap();
+ PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
+ if (vendorHash == null) {
+ vendorHash = new PrinterHashMap();
+ }
+ mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
+ mVendorHashMap.put(vendor, vendorHash);
}
- mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
- mVendorHashMap.put(vendor, vendorHash);
if (mapsChanged) {
mObserver.dataSetChanged();
}
}
- private synchronized void printerRemoved(NsdServiceInfo nsdServiceInfo) {
+ private void printerRemoved(NsdServiceInfo nsdServiceInfo) {
boolean wasRemoved = false;
- Set<String> vendors = mVendorHashMap.keySet();
- for(String vendor : vendors) {
- PrinterHashMap map = mVendorHashMap.get(vendor);
- wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
- if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
+
+ synchronized (mLock) {
+ Set<String> vendors = mVendorHashMap.keySet();
+ for (String vendor : vendors) {
+ PrinterHashMap map = mVendorHashMap.get(vendor);
+ wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
+ if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
+ }
}
+
if (wasRemoved) {
mObserver.dataSetChanged();
}
}
public void start() {
- stop();
- for(final String service :mServiceType) {
- NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
- @Override
- public void onStartDiscoveryFailed(String s, int i) {
+ synchronized (mLock) {
+ stop();
- }
+ for (final String service : mServiceType) {
+ NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
+ @Override
+ public void onStartDiscoveryFailed(String s, int i) {
- @Override
- public void onStopDiscoveryFailed(String s, int i) {
+ }
- }
+ @Override
+ public void onStopDiscoveryFailed(String s, int i) {
- @Override
- public void onDiscoveryStarted(String s) {
+ }
- }
+ @Override
+ public void onDiscoveryStarted(String s) {
- @Override
- public void onDiscoveryStopped(String s) {
+ }
- }
+ @Override
+ public void onDiscoveryStopped(String s) {
- @Override
- public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
- mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
- }
+ }
- @Override
- public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
- mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
- printerRemoved(nsdServiceInfo);
- }
- };
- DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
- mListeners.add(listener);
+ @Override
+ public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
+ mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
+ }
+
+ @Override
+ public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
+ mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
+ printerRemoved(nsdServiceInfo);
+ }
+ };
+ DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
+ mListeners.add(listener);
+ }
}
}
public void stop() {
- for(NsdManager.DiscoveryListener listener : mListeners) {
- DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
+ synchronized (mLock) {
+ for (NsdManager.DiscoveryListener listener : mListeners) {
+ DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
+ }
+ mVendorHashMap.clear();
+ mListeners.clear();
}
- mVendorHashMap.clear();
- mListeners.clear();
}
/**
@@ -183,8 +202,10 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
public ArrayList<InetAddress> getPrinters() {
ArrayList<InetAddress> printerAddressess = new ArrayList<>();
- for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) {
- printerAddressess.addAll(oneVendorPrinters.getPrinterAddresses());
+ synchronized (mLock) {
+ for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) {
+ printerAddressess.addAll(oneVendorPrinters.getPrinterAddresses());
+ }
}
return printerAddressess;
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 16029ee2b3b0..d042c0f89b1e 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -508,7 +508,7 @@
<string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Да се пита винаги"</string>
<string name="zen_mode_forever" msgid="3339224497605461291">"До изключване"</string>
<string name="time_unit_just_now" msgid="3006134267292728099">"Току-що"</string>
- <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Високоговорител на телефона"</string>
+ <string name="media_transfer_this_device_name" msgid="2716555073132169240">"Високоговорител"</string>
<string name="profile_connect_timeout_subtext" msgid="4043408193005851761">"При свързването възникна проблем. Изключете устройството и го включете отново"</string>
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Аудиоустройство с кабел"</string>
<string name="help_label" msgid="3528360748637781274">"Помощ и отзиви"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 3a45526290e0..fb7d00f866b1 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -555,5 +555,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"מושבת"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות עם חוט"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות חוטיות"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index ac643c3a6e62..c95f8bf2fe39 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഹെഡ്ഫോൺ"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയേർഡ് ഹെഡ്ഫോൺ"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 41ccdeb29f3e..5c80627003cd 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -553,5 +553,5 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vyenye waya vinavyobanwa kichwani"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vya waya"</string>
</resources>
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 482a3812b838..18c2957b1adc 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -173,5 +173,6 @@ public class SecureSettings {
Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
Settings.Secure.TAPS_APP_TO_EXIT,
Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED,
+ Settings.Secure.PANIC_GESTURE_ENABLED,
};
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index b337e609e281..91f3f4af0566 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -260,5 +260,6 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ONE_HANDED_MODE_TIMEOUT, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.TAPS_APP_TO_EXIT, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.PANIC_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a994fdaa4591..27576b107efd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2026,6 +2026,13 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
SecureSettingsProto.EMERGENCY_ASSISTANCE_APPLICATION);
+
+ final long emergencyResponseToken = p.start(SecureSettingsProto.EMERGENCY_RESPONSE);
+ dumpSetting(s, p,
+ Settings.Secure.PANIC_GESTURE_ENABLED,
+ SecureSettingsProto.EmergencyResponse.PANIC_GESTURE_ENABLED);
+ p.end(emergencyResponseToken);
+
dumpSetting(s, p,
Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
SecureSettingsProto.ENHANCED_VOICE_PRIVACY_ENABLED);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d50dc7cba52b..7f7afcbf11f5 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -317,6 +317,11 @@
<!-- Permissions required for CTS test - AdbManagerTest -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
+ <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
+ <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 6ecf303c6dc8..dfc47587b91c 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -140,7 +140,8 @@ android_library {
"testables",
"truth-prebuilt",
"dagger2",
- "jsr330"
+ "jsr330",
+ "WindowManager-Shell",
],
libs: [
"android.test.runner",
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 2a2ba1b0ccaa..14097b12e730 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -39,4 +39,6 @@
-keep public class * extends com.android.systemui.SystemUI {
public <init>(android.content.Context);
-} \ No newline at end of file
+}
+
+-keep class com.android.wm.shell.* \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_action.xml b/packages/SystemUI/res/layout/pip_menu_action.xml
deleted file mode 100644
index 3ad35460d8b9..000000000000
--- a/packages/SystemUI/res/layout/pip_menu_action.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<ImageButton
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/pip_action_size"
- android:layout_height="@dimen/pip_action_size"
- android:padding="@dimen/pip_action_padding"
- android:background="?android:selectableItemBackgroundBorderless"
- android:forceHasOverlappingRendering="false" />
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 5c00af5705e9..436188a83d4f 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -62,7 +62,7 @@
android:gravity="center_vertical"
android:focusable="true"
android:singleLine="true"
- android:ellipsize="end"
+ android:ellipsize="marquee"
android:textAppearance="@style/TextAppearance.QS.Status"
android:layout_marginEnd="4dp"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/layout/tv_pip_custom_control.xml b/packages/SystemUI/res/layout/tv_pip_custom_control.xml
deleted file mode 100644
index dd0fce466576..000000000000
--- a/packages/SystemUI/res/layout/tv_pip_custom_control.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<com.android.systemui.pip.tv.PipControlButtonView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/picture_in_picture_button_width"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/picture_in_picture_button_start_margin" />
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
deleted file mode 100644
index 35f2af4f7526..000000000000
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- 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.systemui.pip.tv.PipControlsView
- android:id="@+id/pip_controls"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:alpha="0" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 39660d230575..e48fe656d187 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Wysig volgorde van instellings."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Bladsy <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Sluitskerm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Vou uit"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimeer"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Maak toe"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Instellings"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Swiep af om toe te maak"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Kieslys"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in beeld-in-beeld"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"As jy nie wil hê dat <xliff:g id="NAME">%s</xliff:g> hierdie kenmerk moet gebruik nie, tik om instellings oop te maak en skakel dit af."</string>
- <string name="pip_play" msgid="333995977693142810">"Speel"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Laat wag"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Slaan oor na volgende"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Slaan oor na vorige"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Verander grootte"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Foon afgeskakel weens hitte"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Jou foon werk nou normaal"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Jou foon werk nou normaal.\nTik vir meer inligting"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Jou foon was te warm en dit het afgeskakel om af te koel. Jou foon werk nou normaal.\n\nJou foon kan dalk te warm word as jy:\n • Hulpbron-intensiewe programme (soos dobbel-, video- of navigasieprogramme) gebruik\n • Groot lêers af- of oplaai\n • Jou foon in hoë temperature gebruik"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sien versorgingstappe"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Foon raak warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Sommige kenmerke is beperk terwyl foon afkoel"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Sommige kenmerke is beperk terwyl foon afkoel.\nTik vir meer inligting"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Jou foon sal outomaties probeer om af te koel. Jy kan steeds jou foon gebruik, maar dit sal dalk stadiger wees.\n\nJou foon sal normaalweg werk nadat dit afgekoel het."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sien versorgingstappe"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Trek laaier uit"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kan nie hierdie toestel laai nie. Trek die kragprop uit, en wees versigtig, want die kabel kan warm wees."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sien versorgingstappe"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 62314c054744..f09a7e719332 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"የቅንብሮድ ቅደም-ተከተል አርትዕ።"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ገጽ <xliff:g id="ID_1">%1$d</xliff:g> ከ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ማያ ገጽ ቁልፍ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ዘርጋ"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"አሳንስ"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ዝጋ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ቅንብሮች"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ለማሰናበት ወደ ታች ይጎትቱ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ምናሌ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> በስዕል-ላይ-ስዕል ውስጥ ነው"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ይህን ባህሪ እንዲጠቀም ካልፈለጉ ቅንብሮችን ለመክፈት መታ ያድርጉና ያጥፉት።"</string>
- <string name="pip_play" msgid="333995977693142810">"አጫውት"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ባለበት አቁም"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ወደ ቀጣይ ዝለል"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ወደ ቀዳሚ ዝለል"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"መጠን ይቀይሩ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ስልክ በሙቀት ምክንያት ጠፍቷል"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"የእርስዎ ስልክ አሁን በመደበኝነት እያሄደ ነው"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"የእርስዎ ስልክ በጣም ግሎ ነበር፣ ስለዚህ እንዲቀዘቅዝ ጠፍቷል። የእርስዎ ስልክ አሁን በመደበኝነት እያሄደ ነው።\n\nየሚከተሉትን ካደረጉ የእርስዎ በጣም ሊግል ይችላል፦\n • ኃይል በጣም የሚጠቀሙ መተግበሪያዎችን (እንደ ጨዋታ፣ ቪዲዮ ወይም የአሰሳ መተግበሪያዎች ያሉ) ከተጠቀሙ\n • ትላልቅ ፋይሎችን ካወረዱ ወይም ከሰቀሉ\n • ስልክዎን በከፍተኛ ሙቀት ውስጥ ከተጠቀሙ"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ስልኩ እየሞቀ ነው"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ስልኩ እየቀዘቀዘ ሳለ አንዳንድ ባህሪዎች ይገደባሉ"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"የእርስዎ ስልክ በራስ-ሰር ለመቀዝቀዝ ይሞክራል። አሁንም ስልክዎን መጠቀም ይችላሉ፣ ነገር ግን ሊንቀራፈፍ ይችላል።\n\nአንዴ ስልክዎ ከቀዘቀዘ በኋላ በመደበኝነት ያሄዳል።"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ኃይል መሙያን ይንቀሉ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"የዚህን መሣሪያ ባትሪ መሙላት ላይ ችግር አለ። የኃይል አስማሚውን ይንቀሉትና ሊግል ስለሚችል ገመዱን ይጠብቁት።"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"የእንክብካቤ ደረጃዎችን ይመልከቱ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1af73a05a6f4..7f2a405efed2 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -936,25 +936,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"تعديل ترتيب الإعدادات."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"الصفحة <xliff:g id="ID_1">%1$d</xliff:g> من <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"شاشة القفل"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"توسيع"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"تصغير"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"إغلاق"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"الإعدادات"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"اسحب لأسفل للإلغاء"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"القائمة"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> يظهر في صورة داخل صورة"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"إذا كنت لا تريد أن يستخدم <xliff:g id="NAME">%s</xliff:g> هذه الميزة، فانقر لفتح الإعدادات، ثم أوقِف تفعيل هذه الميزة."</string>
- <string name="pip_play" msgid="333995977693142810">"تشغيل"</string>
- <string name="pip_pause" msgid="1139598607050555845">"إيقاف مؤقت"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"التخطي إلى التالي"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"التخطي إلى السابق"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"تغيير الحجم"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"تم إيقاف الهاتف بسبب الحرارة"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"يعمل هاتفك الآن بشكل طبيعي"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"يعمل هاتفك الآن بشكل طبيعي.\nانقر للحصول على مزيد من المعلومات."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ارتفعت درجة حرارة هاتفك بشدة، لذا تم إيقاف تشغيله لخفض درجة حرارته. يعمل هاتفك الآن بشكل طبيعي.\n\nقد ترتفع بشدة درجة حرارة هاتفك إذا:\n • استخدمت تطبيقات كثيفة الاستخدام لموارد الجهاز (مثل الألعاب أو الفيديو أو تطبيقات التنقل)\n • نزَّلت أو حمَّلت ملفات كبيرة الحجم\n • استخدمت هاتفك وسط أجواء مرتفعة الحرارة"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"الاطّلاع على خطوات العناية"</string>
<string name="high_temp_title" msgid="2218333576838496100">"تزداد درجة حرارة الهاتف"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"يتم تقييد عمل بعض الميزات إلى أن تنخفض درجة حرارة الهاتف.\nانقر للحصول على مزيد من المعلومات."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"سيحاول الهاتف تخفيض درجة حرارته تلقائيًا. سيظل بإمكانك استخدام هاتفك، ولكن قد يعمل بشكل أبطأ.\n\nبعد أن تنخفض درجة حرارة الهاتف، سيستعيد سرعته المعتادة."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"الاطّلاع على خطوات العناية"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"فصل الشاحن"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"هناك مشكلة في شحن هذا الجهاز. يُرجى فصل محوِّل الطاقة بحرص لأن الكابل قد يكون ساخنًا."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"الاطّلاع على خطوات العناية"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index d750bc969aa7..0345af07cd91 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ছেটিংসমূহৰ ক্ৰম সম্পাদনা কৰক।"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>ৰ পৃষ্ঠা <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্ৰীণ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"বিস্তাৰ কৰক"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"সৰু কৰক"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"বন্ধ কৰক"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ছেটিংসমূহ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"অগ্ৰাহ্য কৰিবলৈ তললৈ টানক"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"মেনু"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> চিত্ৰৰ ভিতৰৰ চিত্ৰত আছে"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"আপুনি যদি <xliff:g id="NAME">%s</xliff:g> সুবিধাটো ব্যৱহাৰ কৰিব নোখোজে, তেন্তে ছেটিংসমূহ খুলিবলৈ টিপক আৰু তালৈ গৈ ইয়াক অফ কৰক।"</string>
- <string name="pip_play" msgid="333995977693142810">"প্লে কৰক"</string>
- <string name="pip_pause" msgid="1139598607050555845">"পজ কৰক"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"পৰৱৰ্তী মিডিয়ালৈ যাওক"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"আগৰটো মিডিয়ালৈ যাওক"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"আকাৰ সলনি কৰক"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"আপোনাৰ ফ\'নটো গৰম হোৱাৰ কাৰণে অফ কৰা হৈছিল"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"আপোনাৰ ফ\'নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"আপোনাৰ ফ’নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\nঅধিক তথ্যৰ বাবে টিপক"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"আপোনাৰ ফ\'নটো অত্যধিক গৰম হোৱাৰ বাবে ইয়াক ঠাণ্ডা কৰিবলৈ অফ কৰা হৈছিল। আপোনাৰ ফ\'নটো এতিয়া স্বাভাৱিকভাৱে চলি আছে।\n\nআপোনাৰ ফ\'নটো গৰম হ\'ব পাৰে, যদিহে আপুনি:\n • ফ\'নটোৰ হাৰ্ডৱেৰ অত্যধিক মাত্ৰাত ব্যৱহাৰ কৰা এপসমূহ চলালে (যেনে, ভিডিঅ\' গেইম, ভিডিঅ\', দিক্-নিৰ্দেশনা এপসমূহ)\n • খুউব ডাঙৰ আকাৰৰ ফাইল আপল\'ড বা ডাউনল’ড কৰিলে\n • আপোনাৰ ফ\'নটো উচ্চ তাপমাত্ৰাৰ পৰিৱেশত ব্যৱহাৰ কৰিলে"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ফ\'নটো গৰম হ\'বলৈ ধৰিছে"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ফ\'নটো ঠাণ্ডা হৈ থকা সময়ত কিছুমান সুবিধা উপলব্ধ নহ’ব"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ফ’নটো ঠাণ্ডা হৈ থকাৰ সময়ত কিছুমান সুবিধা উপলব্ধ নহয়।\nঅধিক তথ্যৰ বাবে টিপক"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"আপোনাৰ ফ\'নটোৱে নিজে নিজে ঠাণ্ডা হ\'বলৈ স্বয়ংক্ৰিয়ভাৱে চেষ্টা কৰিব। আপুনি ফ\'নটো ব্যৱহাৰ কৰি থাকিব পাৰে কিন্তু ই লাহে লাহে চলিব পাৰে।\n\nফ\'নটো সম্পূৰ্ণভাৱে ঠাণ্ডা হোৱাৰ পিছত ই আগৰ নিচিনাকৈয়েই চলিব।"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"চ্চার্জাৰ আনপ্লাগ কৰক"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইচটো চ্চার্জ কৰোঁতে কিবা সমস্যা হৈছে। পাৱাৰ এডাপ্টাৰটো আনপ্লাগ কৰক, কেব’লডাল গৰম হ’ব পাৰে গতিকে সাবধান হ’ব।"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"যত্ন লোৱাৰ পদক্ষেপসমূহ চাওক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 59c9ba6b5f7c..d0025306d203 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ayarların sıralanmasını redaktə edin."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> səhifədən <xliff:g id="ID_1">%1$d</xliff:g> səhifə"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran kilidi"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Genişləndirin"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Kiçildin"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Bağlayın"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ayarlar"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Rədd etmək üçün aşağı çəkin"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menyu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> şəkil içində şəkildədir"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> tətbiqinin bu funksiyadan istifadə etməyini istəmirsinizsə, ayarları açmaq və deaktiv etmək üçün klikləyin."</string>
- <string name="pip_play" msgid="333995977693142810">"Oxudun"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Fasilə verin"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Növbətiyə keçin"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Əvvəlkinə keçin"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ölçüsünü dəyişin"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"İstiliyə görə telefon söndü"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon indi normal işləyir"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonunuz indi normal işləyir.\nƏtraflı məlumat üçün toxunun"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon çox isti idi və soyumaq üçün söndü. Hazırda telefon normal işləyir.\n\n Telefon bu hallarda çox isti ola bilər:\n • Çox resurslu tətbiq istifadə etsəniz (oyun, video və ya naviqasiya tətbiqi kimi)\n • Böyük həcmli fayl endirsəniz və ya yükləsəniz\n • Telefonu yüksək temperaturda istifadə etsəniz"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon qızmağa başlayır"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soyuyana kimi bəzi funksiyalar məhdudlaşdırılır.\nƏtraflı məlumat üçün toxunun"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz avtomatik olaraq soyumağa başlayacaq. Telefon istifadəsinə davam edə bilərsiniz, lakin sürəti yavaşlaya bilər.\n\nTelefonunuz soyuduqdan sonra normal işləyəcək."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ehtiyat tədbiri mərhələlərinə baxın"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Adapteri cərəyandan ayırın"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihazın batareya yığmasında problem var. Adapteri cərəyandan ayırın. Ehtiyatlı olun, kabel isti ola bilər."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ehtiyat tədbiri mərhələlərinə baxı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 8cf7d0bdd008..5cca958bbe96 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Izmeni redosled podešavanja."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključan ekran"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Proširi"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Umanji"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zatvori"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Podešavanja"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Prevucite nadole da biste odbili"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meni"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> je slika u slici"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da biste otvorili podešavanja i isključili je."</string>
- <string name="pip_play" msgid="333995977693142810">"Pusti"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pauziraj"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Pređi na sledeće"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Pređi na prethodno"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Promenite veličinu"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog toplote"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon sada normalno radi"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon sada normalno radi.\nDodirnite za više informacija"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon je bio prevruć, pa se isključio da se ohladi. Sada radi normalno.\n\nTelefon može previše da se ugreje ako:\n • Koristite aplikacije koje zahtevaju puno resursa (npr. video igre, video ili aplikacije za navigaciju)\n • Preuzimate/otpremate velike datoteke\n • Koristite telefon na visokoj temperaturi"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte upozorenja"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon se zagrejao"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Neke funkcije su ograničene dok se telefon ne ohladi"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će automatski pokušati da se ohladi. I dalje ćete moći da koristite telefon, ali će sporije reagovati.\n\nKada se telefon ohladi, normalno će raditi."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte upozorenja"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač iz napajanja"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema sa punjenjem ovog uređaja. Isključite adapter iz napajanja i budite pažljivi jer kabl može da bude topao."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upozorenja"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 805fe3ac4288..956ef477c927 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Змяніць парадак налад."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Экран блакіроўкі"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Разгарнуць"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Згарнуць"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Закрыць"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Налады"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Перацягніце ўніз, каб адхіліць"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Меню"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> з’яўляецца відарысам у відарысе"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Калі вы не хочаце, каб праграма <xliff:g id="NAME">%s</xliff:g> выкарыстоўвала гэту функцыю, дакраніцеся, каб адкрыць налады і адключыць яе."</string>
- <string name="pip_play" msgid="333995977693142810">"Прайграць"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Прыпыніць"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Перайсці да наступнага"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Перайсці да папярэдняга"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Змяніць памер"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"З-за перагрэву тэл. выключыўся"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Тэлефон працуе нармальна"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ваш тэлефон працуе нармальна.\nНацісніце, каб даведацца больш"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ваш тэлефон пераграваўся, таму ён выключыўся, каб астыць. Зараз тэлефон працуе нармальна.\n\nТэлефон можа перагравацца пры:\n • Выкарыстанні рэсурсаёмістых праграм (напрыклад, гульняў, відэа або праграм навігацыі)\n • Спампоўцы або запампоўцы вялікіх файлаў\n • Выкарыстанні тэлефона пры высокіх тэмпературах"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Глядзець паэтапную дапамогу"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Тэлефон награваецца"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Некаторыя функцыі абмежаваны, пакуль тэлефон астывае"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Некаторыя функцыі абмежаваны, пакуль тэлефон не астыне.\nНацісніце, каб даведацца больш"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш тэлефон аўтаматычна паспрабуе астыць. Вы можаце па-ранейшаму карыстацца сваім тэлефонам, але ён можа працаваць больш павольна.\n\nПасля таго як ваш тэлефон астыне, ён будзе працаваць у звычайным рэжыме."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Глядзець паэтапную дапамогу"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Адключыце зарадную прыладу"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Узнікла праблема з зарадкай гэтай прылады. Адключыце адаптар сілкавання і праверце, ці не нагрэўся кабель."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Глядзець паэтапную дапамогу"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6b99aeb7ca7b..d0836e4509fe 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Редактиране на подредбата на настройките."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> от <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заключен екран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Разгъване"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Намаляване"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Затваряне"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Настройки"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Преместете надолу с плъзгане, за да отхвърлите"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Меню"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> е в режима „Картина в картината“"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ако не искате <xliff:g id="NAME">%s</xliff:g> да използва тази функция, докоснете, за да отворите настройките, и я изключете."</string>
- <string name="pip_play" msgid="333995977693142810">"Пускане"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Поставяне на пауза"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Към следващия елемент"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Към предишния елемент"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Преоразмеряване"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Тел. се изкл. поради загряване"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Телефонът ви вече работи нормално"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефонът ви вече работи нормално.\nДокоснете за още информация"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонът ви бе твърде горещ, затова се изключи с цел охлаждане. Вече работи нормално.\n\nТелефонът ви може да стане твърде горещ, ако:\n • използвате приложения, които ползват голям обем ресурси (като например игри, видеосъдържание или приложения за навигация);\n • изтегляте или качвате големи файлове;\n • използвате устройството си при високи температури."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Вижте стъпките, които да предприемете"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефонът загрява"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Някои функции са ограничени, докато телефонът се охлажда"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Някои функции са ограничени, докато телефонът се охлажда.\nДокоснете за още информация"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонът ви автоматично ще направи опит за охлаждане. Пак можете да го използвате, но той може да работи по-бавно.\n\nСлед като се охлади, ще работи нормално."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Вижте стъпките, които да предприемете"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Изключете зарядното устройство"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"При зареждането на това устройство възникна проблем. Изключете захранващия адаптер и внимавайте, тъй като кабелът може да е топъл."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Вижте стъпките, които да предприемете"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 3e0adea9262a..1be233d02876 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ক্রম বা সেটিংস সম্পাদনা করুন৷"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>টির মধ্যে <xliff:g id="ID_1">%1$d</xliff:g> নং পৃষ্ঠা"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"লক স্ক্রিন"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"বড় করুন"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ছোটো করুন"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"বন্ধ করুন"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"সেটিংস"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"খারিজ করতে নিচের দিকে টেনে আনুন"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"মেনু"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"ছবির-মধ্যে-ছবি তে <xliff:g id="NAME">%s</xliff:g> আছেন"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> কে এই বৈশিষ্ট্যটি ব্যবহার করতে দিতে না চাইলে ট্যাপ করে সেটিংসে গিয়ে সেটি বন্ধ করে দিন।"</string>
- <string name="pip_play" msgid="333995977693142810">"চালান"</string>
- <string name="pip_pause" msgid="1139598607050555845">"বিরাম দিন"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"এগিয়ে যাওয়ার জন্য এড়িয়ে যান"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"পিছনে যাওয়ার জন্য এড়িয়ে যান"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"রিসাইজ করুন"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"আপনার ফোন গরম হওয়ার জন্য বন্ধ হয়ে গেছে"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"আপনার ফোন এখন ঠিক-ঠাক চলছে"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"আপনার ফোন খুব বেশি গরম হয়েছিল বলে ঠাণ্ডা হওয়ার জন্য বন্ধ হয়ে গেছে। আপনার ফোন ঠিক-ঠাক ভাবে চলছে না।\n\nআপনার ফোন খুব বেশি গরম হয়ে যাবে যদি আপনি:\n •এমন অ্যাপ ব্যবহার করলে যেটি আপনার ডিভাইসের রিসোর্স বেশি ব্যবহার করে (যেমন গেমিং, ভিডিও বা নেভিগেশন অ্যাপ)\n • বড় ফাইল ডাউনলোড বা আপলোড করলে\n • বেশি তাপমাত্রায় আপনার ফোন ব্যবহার করলে"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ফোনটি গরম হচ্ছে"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ফোনটি ঠাণ্ডা হওয়ার সময় কিছু বৈশিষ্ট্য সীমিত হতে পারে"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"আপনার ফোনটি নিজে থেকেই ঠাণ্ডা হওয়ার চেষ্টা করবে৷ আপনি তবুও আপনার ফোন ব্যবহার করতে পারেন, কিন্তু এটি একটু ধীরে চলতে পারে৷\n\nআপনার ফোনটি পুরোপুরি ঠাণ্ডা হয়ে গেলে এটি স্বাভাবিকভাবে চলবে৷"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"চার্জার আনপ্লাগ করুন"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"এই ডিভাইস চার্জ করার সময় সমস্যা হয়েছে। চার্জিং কেবলটি হয়ত গরম হয়ে গেছে, পাওয়ার অ্যাডাপ্টারটি আনপ্লাগ করুন।"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"কী করতে হবে ধাপে ধাপে দেখুন"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d9cfd9d5bc62..4c872d22054f 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Urediti raspored postavki."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključavanje ekrana"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Proširi"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimiziraj"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zatvori"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Postavke"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Povucite prema dolje da odbacite"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meni"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> je u načinu priakza Slika u slici"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ako ne želite da <xliff:g id="NAME">%s</xliff:g> koristi ovu funkciju, dodirnite da otvorite postavke i isključite je."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproduciraj"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pauziraj"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Preskoči na sljedeći"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Preskoči na prethodni"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Promjena veličine"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog pregrijavanja"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Vaš telefon sada radi normalno"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Vaš telefon sada radi normalno.\nDodirnite za više informacija"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Vaš telefon se pregrijao, pa se isključio da se ohladi. Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • Koristite aplikacije koje troše puno resursa (kao što su aplikacije za igranje, videozapise ili navigaciju)\n • Preuzimate ili otpremate velike fajlove\n • Koristite telefon na visokim temperaturama"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pogledajte korake za zaštitu"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon se pregrijava"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Neke funkcije su ograničene dok se telefon hladi"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke funkcije su ograničene dok se telefon hladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Vaš telefon će se automatski pokušati ohladiti. I dalje možete koristi telefon, ali će možda raditi sporije.\n\nNakon što se ohladi, telefon će normalno raditi."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pogledajte korake za zaštitu"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Isključite punjač"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Došlo je do problema prilikom punjenja ovog uređaja. Pažljivo isključite adapter za napajanje jer je moguće da je kabl vruć."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Prikaz koraka za zaštitu"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4c2cd6df4c3c..61b8e814eacb 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edita l\'ordre de la configuració."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pàgina <xliff:g id="ID_1">%1$d</xliff:g> (<xliff:g id="ID_2">%2$d</xliff:g> en total)"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueig"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Desplega"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimitza"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Tanca"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Configuració"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrossega cap avall per ignorar-ho"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menú"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> està en pantalla en pantalla"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Si no vols que <xliff:g id="NAME">%s</xliff:g> utilitzi aquesta funció, toca per obrir la configuració i desactiva-la."</string>
- <string name="pip_play" msgid="333995977693142810">"Reprodueix"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Posa en pausa"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Ves al següent"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Torna a l\'anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Canvia la mida"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telèfon apagat per la calor"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Ara el telèfon funciona de manera normal"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ara el telèfon funciona correctament.\nToca per obtenir més informació"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"El telèfon s\'havia sobreescalfat i s\'ha apagat per refredar-se. Ara funciona amb normalitat.\n\nEs pot sobreescalfar si:\n • utilitzes aplicacions que consumeixen molts recursos (com ara, videojocs, vídeos o aplicacions de navegació);\n • baixes o penges fitxers grans;\n • l\'utilitzes amb temperatures altes."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Mostra els passos de manteniment"</string>
<string name="high_temp_title" msgid="2218333576838496100">"El telèfon s\'està escalfant"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Algunes funcions estaran limitades mentre el telèfon es refreda"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunes funcions estan limitades mentre el telèfon es refreda.\nToca per obtenir més informació"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"El telèfon provarà de refredar-se automàticament. Podràs continuar utilitzant-lo, però és possible que funcioni més lentament.\n\nUn cop s\'hagi refredat, funcionarà amb normalitat."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Mostra els passos de manteniment"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconnecta el carregador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No es pot carregar el dispositiu. Desconnecta l\'adaptador de corrent amb compte, ja que el cable podria estar calent."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Mostra els pasos de manteniment"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 2dd314dffdfe..29b5281f689f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Upravit pořadí nastavení."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stránka <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Obrazovka uzamčení"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Rozbalit"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimalizovat"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zavřít"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Nastavení"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Nápovědu zavřete přetažením dolů"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Nabídka"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"Aplikace <xliff:g id="NAME">%s</xliff:g> je v režimu obraz v obraze"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Pokud nechcete, aby aplikace <xliff:g id="NAME">%s</xliff:g> tuto funkci používala, klepnutím otevřete nastavení a funkci vypněte."</string>
- <string name="pip_play" msgid="333995977693142810">"Přehrát"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pozastavit"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Přeskočit na další"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Přeskočit na předchozí"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Změnit velikost"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se vypnul z důvodu zahřátí"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Nyní telefon funguje jako obvykle."</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Nyní telefon funguje jako obvykle.\nKlepnutím zobrazíte další informace"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon byl příliš zahřátý, proto se vypnul, aby vychladl. Nyní telefon funguje jako obvykle.\n\nTelefon se může příliš zahřát v těchto případech:\n • používání náročných aplikací (např. her, videí nebo navigace),\n • stahování nebo nahrávání velkých souborů,\n • používání telefonu při vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobrazit pokyny, co dělat"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon se zahřívá"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Některé funkce jsou při chladnutí omezeny"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Některé funkce jsou při chladnutí telefonu omezeny.\nKlepnutím zobrazíte další informace"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se automaticky pokusí vychladnout. Lze jej nadále používat, ale může být pomalejší.\n\nAž telefon vychladne, bude fungovat normálně."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobrazit pokyny, co dělat"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíječku"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Při nabíjení zařízení došlo k problému. Odpojte napájecí adaptér (dávejte pozor, kabel může být horký)."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobrazit pokyny, co dělat"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 701c0d6f2b78..dff770d49e28 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Rediger rækkefølgen af indstillinger."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskærm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Udvid"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimer"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Luk"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Indstillinger"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Træk ned for at fjerne"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> vises som integreret billede"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Hvis du ikke ønsker, at <xliff:g id="NAME">%s</xliff:g> skal benytte denne funktion, kan du åbne indstillingerne og deaktivere den."</string>
- <string name="pip_play" msgid="333995977693142810">"Afspil"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Sæt på pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Gå videre til næste"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Gå til forrige"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Rediger størrelse"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonen slukkede pga. varme"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Din telefon kører nu normalt"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Din telefon kører nu normalt.\nTryk for at få flere oplysninger"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Din telefon var blevet for varm, så den slukkede for at køle ned. Din telefon kører nu igen normalt. \n\nDin telefon kan blive for varm, hvis du:\n • Bruger ressourcekrævende apps (f.eks. spil, video eller navigation)\n • Downloader eller uploader store filer\n • Bruger din telefon i varme omgivelser"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se håndteringsvejledning"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefonen er ved at blive varm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Nogle funktioner er begrænsede, mens telefonen køler ned"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Nogle funktioner er begrænsede, mens telefonen køler ned.\nTryk for at få flere oplysninger"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Din telefon forsøger automatisk at køle ned. Du kan stadig bruge telefonen, men den kører muligvis langsommere.\n\nNår din telefon er kølet ned, fungerer den normalt igen."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se håndteringsvejledning"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Frakobl opladeren"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Der er et problem med opladning af denne enhed. Frakobl strømadapteren, og vær forsigtig, da kablet kan være varmt."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vejledningen i pleje"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c80b6e0840bf..ccb7d14395b6 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Reihenfolge der Einstellungen bearbeiten."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Seite <xliff:g id="ID_1">%1$d</xliff:g> von <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Sperrbildschirm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Maximieren"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimieren"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Schließen"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Einstellungen"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Zum Verwerfen nach unten ziehen"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menü"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ist in Bild im Bild"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Wenn du nicht möchtest, dass <xliff:g id="NAME">%s</xliff:g> diese Funktion verwendet, tippe, um die Einstellungen zu öffnen und die Funktion zu deaktivieren."</string>
- <string name="pip_play" msgid="333995977693142810">"Wiedergeben"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausieren"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Vorwärts springen"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Rückwärts springen"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Größe anpassen"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Ausgeschaltet, da zu heiß"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Dein Smartphone funktioniert jetzt wieder normal"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Dein Smartphone war zu heiß und wurde zum Abkühlen ausgeschaltet. Nun funktioniert es wieder normal.\n\nMögliche Ursachen:\n • Verwendung ressourcenintensiver Apps (z. B. Spiele-, Video- oder Navigations-Apps)\n • Download oder Upload großer Dateien \n • Verwendung des Smartphones bei hohen Temperaturen"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"Smartphone wird warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Einige Funktionen sind während der Abkühlphase des Smartphones eingeschränkt"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Dein Smartphone kühlt sich automatisch ab. Du kannst dein Smartphone weiterhin nutzen, aber es reagiert möglicherweise langsamer.\n\nSobald dein Smartphone abgekühlt ist, funktioniert es wieder normal."</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Ladegerät vom Stromnetz trennen"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Beim Laden dieses Geräts ist ein Problem aufgetreten. Trenne das Netzteil vom Stromnetz. Sei dabei vorsichtig, denn das Netzteil oder das Kabel könnte heiß sein."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Schritte zur Fehlerbehebung ansehen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0002f607c354..bf4c61994c29 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Επεξεργασία σειράς ρυθμίσεων."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Σελίδα <xliff:g id="ID_1">%1$d</xliff:g> από <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Οθόνη κλειδώματος"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Ανάπτυξη"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Ελαχιστοποίηση"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Κλείσιμο"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ρυθμίσεις"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Σύρετε προς τα κάτω για παράβλεψη"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Μενού"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"Η λειτουργία picture-in-picture είναι ενεργή σε <xliff:g id="NAME">%s</xliff:g>."</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Εάν δεν θέλετε να χρησιμοποιείται αυτή η λειτουργία από την εφαρμογή <xliff:g id="NAME">%s</xliff:g>, πατήστε για να ανοίξετε τις ρυθμίσεις και απενεργοποιήστε την."</string>
- <string name="pip_play" msgid="333995977693142810">"Αναπαραγωγή"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Παύση"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Μετάβαση στο επόμενο"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Μετάβαση στο προηγούμενο"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Αλλαγή μεγέθους"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Το τηλέφωνο απεν. λόγω ζέστης"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Το τηλέφωνο λειτουργεί πλέον κανονικά"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Το τηλέφωνο λειτουργεί πλέον κανονικά.\nΠατήστε για περισσότερες πληροφορίες."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Η θερμοκρασία του τηλεφώνου είναι πολύ υψηλή και απενεργοποιήθηκε για να κρυώσει. Πλέον, λειτουργεί κανονικά.\n\nΗ θερμοκρασία ενδέχεται να ανέβει κατά τη:\n • Χρήση εφαρμογών υψηλής κατανάλωσης πόρων (όπως gaming, βίντεο ή περιήγησης)\n • Λήψη/μεταφόρτωση μεγάλων αρχείων\n • Χρήση σε υψηλές θερμοκρασίες"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Δείτε βήματα αντιμετώπισης."</string>
<string name="high_temp_title" msgid="2218333576838496100">"Αύξηση θερμοκρασίας τηλεφώνου"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Ορισμένες λειτουργίες περιορίζονται κατά τη μείωση της θερμοκρασίας.\nΠατήστε για περισσότερες πληροφορίες."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Το τηλέφωνό σας θα προσπαθήσει να μειώσει αυτόματα τη θερμοκρασία. Μπορείτε να εξακολουθήσετε να το χρησιμοποιείτε, αλλά είναι πιθανό να λειτουργεί πιο αργά.\n\nΜόλις μειωθεί η θερμοκρασία του τηλεφώνου σας, θα λειτουργεί ξανά κανονικά."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Δείτε βήματα αντιμετώπισης."</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Αποσυνδέστε τον φορτιστή"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Υπάρχει κάποιο πρόβλημα με τη φόρτιση αυτής της συσκευής. Αποσυνδέστε τον μετασχηματιστή με προσοχή, λαμβάνοντας υπόψη ότι το καλώδιο μπορεί να είναι ζεστό."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Δείτε βήματα αντιμετώπισης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 83d769d47c88..acb811107463 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expand"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimise"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Close"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Settings"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Drag down to dismiss"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
- <string name="pip_play" msgid="333995977693142810">"Play"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Skip to next"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Skip to previous"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Resize"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Your phone is now running normally"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Some features limited while phone cools down"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 3d549baf3ebd..e3bad1f83a90 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expand"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimise"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Close"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Settings"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Drag down to dismiss"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
- <string name="pip_play" msgid="333995977693142810">"Play"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Skip to next"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Skip to previous"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Resize"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Your phone is now running normally"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Some features limited while phone cools down"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 83d769d47c88..acb811107463 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expand"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimise"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Close"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Settings"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Drag down to dismiss"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
- <string name="pip_play" msgid="333995977693142810">"Play"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Skip to next"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Skip to previous"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Resize"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Your phone is now running normally"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Some features limited while phone cools down"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 83d769d47c88..acb811107463 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit order of settings."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> of <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expand"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimise"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Close"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Settings"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Drag down to dismiss"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"If you don\'t want <xliff:g id="NAME">%s</xliff:g> to use this feature, tap to open settings and turn it off."</string>
- <string name="pip_play" msgid="333995977693142810">"Play"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Skip to next"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Skip to previous"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Resize"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Phone turned off due to heat"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Your phone is now running normally"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Your phone is now running normally.\nTap for more info"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n • Use resource-intensive apps (such as gaming, video or navigation apps)\n • Download or upload large files\n • Use your phone in high temperatures"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"See care steps"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Phone is getting warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Some features limited while phone cools down"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Some features are limited while phone cools down.\nTap for more info"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Your phone will automatically try to cool down. You can still use your phone, but it may run more slowly.\n\nOnce your phone has cooled down, it will run normally."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"See care steps"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Unplug charger"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"There’s an issue charging this device. Unplug the power adaptor, and take care as the cable may be warm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"See care steps"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 13c06f34be3d..25ec6c384157 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎Edit order of settings.‎‏‎‎‏‎"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎Page ‎‏‎‎‏‏‎<xliff:g id="ID_1">%1$d</xliff:g>‎‏‎‎‏‏‏‎ of ‎‏‎‎‏‏‎<xliff:g id="ID_2">%2$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎Lock screen‎‏‎‎‏‎"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎Expand‎‏‎‎‏‎"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎Minimize‎‏‎‎‏‎"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎Close‎‏‎‎‏‎"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎Settings‎‏‎‎‏‎"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎Drag down to dismiss‎‏‎‎‏‎"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎Menu‎‏‎‎‏‎"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ is in picture-in-picture‎‏‎‎‏‎"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎If you don\'t want ‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to use this feature, tap to open settings and turn it off.‎‏‎‎‏‎"</string>
- <string name="pip_play" msgid="333995977693142810">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎Play‎‏‎‎‏‎"</string>
- <string name="pip_pause" msgid="1139598607050555845">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎Pause‎‏‎‎‏‎"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‎Skip to next‎‏‎‎‏‎"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎Skip to previous‎‏‎‎‏‎"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‎Resize‎‏‎‎‏‎"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎Phone turned off due to heat‎‏‎‎‏‎"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‏‎Your phone is now running normally‎‏‎‎‏‎"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎Your phone is now running normally.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap for more info‎‏‎‎‏‎"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎Your phone was too hot, so it turned off to cool down. Your phone is now running normally.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Your phone may get too hot if you:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ • Use resource-intensive apps (such as gaming, video, or navigation apps)‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ • Download or upload large files‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ • Use your phone in high temperatures‎‏‎‎‏‎"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎See care steps‎‏‎‎‏‎"</string>
<string name="high_temp_title" msgid="2218333576838496100">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎Phone is getting warm‎‏‎‎‏‎"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎Some features limited while phone cools down‎‏‎‎‏‎"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎Some features limited while phone cools down.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap for more info‎‏‎‎‏‎"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎Your phone will automatically try to cool down. You can still use your phone, but it may run slower.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Once your phone has cooled down, it will run normally.‎‏‎‎‏‎"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎See care steps‎‏‎‎‏‎"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎Unplug charger‎‏‎‎‏‎"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎There’s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm.‎‏‎‎‏‎"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎See care steps‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index a245b08fba13..01bed104a951 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar orden de configuración"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expandir"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Cerrar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Configuración"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrastra hacia abajo para descartar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menú"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> está en modo de Pantalla en pantalla"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> use esta función, presiona para abrir la configuración y desactivarla."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproducir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Siguiente"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Cambiar el tamaño"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"El teléfono se apagó por calor"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Tu teléfono ya funciona correctamente"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Tu teléfono ahora se ejecuta con normalidad.\nPresiona para obtener más información"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Tu teléfono estaba muy caliente y se apagó para enfriarse. Ya funciona correctamente.\n\nTu teléfono puede calentarse en estos casos:\n • Usas apps que consumen muchos recursos (como juegos, videos o navegación).\n • Subes o descargas archivos grandes.\n • Usas el teléfono en condiciones de temperatura alta."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
<string name="high_temp_title" msgid="2218333576838496100">"El teléfono se está calentando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Se limitarán algunas funciones mientras se enfría el teléfono"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Algunas funciones se limitan durante el enfriamiento del teléfono.\nPresiona para obtener más información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Tu teléfono intentará enfriarse automáticamente. Podrás usarlo, pero es posible que funcione más lento.\n\nUna vez que se haya enfriado, volverá a funcionar correctamente."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconectar cargador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de la corriente con cuidado, ya que el cable podría estar caliente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index d7ab19d359d9..67678d24a0a6 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Cambiar el orden de los ajustes."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Mostrar"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Cerrar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ajustes"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrastra hacia abajo para ignorar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menú"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> está en imagen en imagen"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Si no quieres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca la notificación para abrir los ajustes y desactivarla."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproducir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Saltar al siguiente"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Volver al anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Cambiar tamaño"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Teléfono apagado por calor"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"El teléfono ahora funciona con normalidad"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"El teléfono ya funciona con normalidad.\nToca para ver más información"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"El teléfono se había calentado demasiado y se ha apagado para enfriarse. Ahora funciona con normalidad.\n\nPuede calentarse demasiado si:\n • Usas aplicaciones que consumen muchos recursos (p. ej., apps de juegos, vídeos o navegación)\n • Descargas o subes archivos grandes\n • Lo usas a altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantenimiento"</string>
<string name="high_temp_title" msgid="2218333576838496100">"El teléfono se está calentando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Se limitan algunas funciones mientras el teléfono se enfría"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Se han limitado algunas funciones mientras el teléfono se enfría.\nToca para ver más información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"El teléfono intentará enfriarse. Puedes seguir utilizándolo, pero es posible que funcione con mayor lentitud.\n\nUna vez que se haya enfriado, funcionará con normalidad."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantenimiento"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta el cargador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"No se puede cargar el dispositivo. Desconecta el adaptador de corriente con cuidado, ya que el cable puede estar caliente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantenimiento"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ca43ac0ef13a..a46fa490b4a8 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Muuda seadete järjestust."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Leht <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lukustuskuva"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Laiendamine"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimeeri"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Sule"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Seaded"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Loobumiseks lohistage alla"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menüü"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> on režiimis Pilt pildis"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Kui te ei soovi, et rakendus <xliff:g id="NAME">%s</xliff:g> seda funktsiooni kasutaks, puudutage seadete avamiseks ja lülitage see välja."</string>
- <string name="pip_play" msgid="333995977693142810">"Esita"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Peata"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Järgmise juurde"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Eelmise juurde"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Suuruse muutmine"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Tel. lül. kuumuse tõttu välja"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon töötab nüüd tavapäraselt"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon töötab nüüd tavapäraselt.\nPuudutage lisateabe saamiseks."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon oli liiga kuum, seetõttu lülitus see jahtumiseks välja. Telefon töötab nüüd tavapäraselt.\n\nTelefon võib kuumaks minna:\n • ressursse koormavate rakenduste kasutamisel (nt mängu-, video- või navigatsioonirakendused)\n • suurte failide alla-/üleslaadimisel\n • telefoni kasutamisel kõrgel temperatuuril"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vaadake hooldusjuhiseid"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon soojeneb"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Mõned funktsioonid on piiratud, kuni telefon jahtub"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Mõned funktsioonid on piiratud, kuni telefon jahtub.\nPuudutage lisateabe saamiseks."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Teie telefon proovib automaatselt maha jahtuda. Saate telefoni ikka kasutada, kuid see võib olla aeglasem.\n\nKui telefon on jahtunud, töötab see tavapäraselt."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vaadake hooldusjuhiseid"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Eemaldage laadija vooluvõrgust"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Selle seadme laadimisega on probleem. Eemaldage toiteadapter ja olge ettevaatlik, sest kaabel võib olla soe."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vaadake hooldusjuhiseid"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index ed5dc7cfca3f..19fc4f50d0d3 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editatu ezarpenen ordena."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g> orria"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantaila blokeatua"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Zabaldu"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizatu"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Itxi"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ezarpenak"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Baztertzeko, arrastatu behera"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menua"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"Pantaila txiki gainjarrian dago <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ez baduzu nahi <xliff:g id="NAME">%s</xliff:g> zerbitzuak eginbide hori erabiltzea, sakatu hau ezarpenak ireki eta aukera desaktibatzeko."</string>
- <string name="pip_play" msgid="333995977693142810">"Erreproduzitu"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausatu"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Saltatu hurrengora"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Saltatu aurrekora"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Aldatu tamaina"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Beroegi egoteagatik itzali da"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Orain, ohiko moduan dabil telefonoa"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ohi bezala ari da funtzionatzen telefonoa orain.\nInformazio gehiago lortzeko, sakatu hau."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonoa gehiegi berotu da, eta itzali egin da tenperatura jaisteko. Orain, ohiko moduan dabil.\n\nBerotzearen zergati posibleak:\n • Baliabide asko behar dituzten aplikazioak erabiltzea (adib., jokoak, bideoak edo nabigazio-aplikazioak).\n • Fitxategi handiak deskargatu edo kargatzea.\n • Telefonoa giro beroetan erabiltzea."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ikusi zaintzeko urratsak"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Berotzen ari da telefonoa"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Eginbide batzuk ezingo dira erabili telefonoa hoztu arte.\nInformazio gehiago lortzeko, sakatu hau."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonoa automatikoki saiatuko da hozten. Hoztu bitartean, telefonoa erabiltzen jarrai dezakezu, baina mantsoago funtziona lezake.\n\nTelefonoaren tenperatura jaitsi bezain laster, ohi bezala funtzionatzen jarraituko du."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ikusi zaintzeko urratsak"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Deskonektatu kargagailua"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Arazo bat izan da gailua kargatzean. Deskonektatu egokigailua eta kontuz ibili, kablea bero egon baitaiteke."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ikusi zaintzeko urratsak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 6be188060734..b8c87938d423 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ویرایش ترتیب تنظیمات."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحه <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"صفحه قفل"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"بزرگ کردن"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"کوچک کردن"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"بستن"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"تنظیمات"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"برای نپذیرفتن، به پایین بکشید"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"منو"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> درحالت تصویر در تصویر است"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"اگر نمی‌خواهید <xliff:g id="NAME">%s</xliff:g> از این قابلیت استفاده کند، با ضربه زدن، تنظیمات را باز کنید و آن را خاموش کنید."</string>
- <string name="pip_play" msgid="333995977693142810">"پخش"</string>
- <string name="pip_pause" msgid="1139598607050555845">"توقف موقت"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"رد شدن به بعدی"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"رد شدن به قبلی"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"تغییر اندازه"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"تلفن به علت گرم شدن خاموش شد"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"اکنون تلفنتان عملکرد معمولش را دارد"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"اکنون عملکرد تلفنتان به حالت عادی برگشته است.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"تلفنتان خیلی گرم شده بود، بنابراین خاموش شد تا خنک شود. اکنون تلفنتان عملکرد معمولش را دارد.\n\nتلفنتان خیلی گرم می‌شود، اگر:\n • از برنامه‌های نیازمند پردازش زیاد (مانند بازی، برنامه‌های ویدیویی یا پیمایشی) استفاده کنید\n • فایل‌های بزرگ بارگیری یا بارگذاری کنید\n • در دماهای بالا از تلفنتان استفاده کنید"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"دیدن اقدامات محافظتی"</string>
<string name="high_temp_title" msgid="2218333576838496100">"تلفن درحال گرم شدن است"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"وقتی تلفن درحال خنک شدن است، بعضی از قابلیت‌ها محدود می‌شوند"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"وقتی تلفن درحال خنک شدن است، بعضی از ویژگی‌ها محدود می‌شوند.\nبرای اطلاعات بیشتر ضربه بزنید"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"تلفنتان به‌طور خودکار سعی می‌کند خنک شود. همچنان می‌توانید از تلفنتان استفاده کنید، اما ممکن است کندتر عمل کند.\n\nوقتی تلفن خنک شد، عملکرد عادی‌اش از سرگرفته می‌شود."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"دیدن اقدامات محافظتی"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"جدا کردن شارژر از برق"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"مشکلی در شارژ کردن این دستگاه وجود دارد. آداپتور برق را از برق جدا کنید و مراقب باشید زیرا ممکن است کابل گرم باشد."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"مشاهده مراحل احتیاط"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cfbd4d52ab18..44a66c31b954 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Muokkaa asetusten järjestystä."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sivu <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lukitusnäyttö"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Laajenna"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Pienennä"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Sulje"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Asetukset"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Hylkää vetämällä alas."</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Valikko"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> on kuva kuvassa ‑tilassa"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Jos et halua, että <xliff:g id="NAME">%s</xliff:g> voi käyttää tätä ominaisuutta, avaa asetukset napauttamalla ja poista se käytöstä."</string>
- <string name="pip_play" msgid="333995977693142810">"Toista"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Keskeytä"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Siirry seuraavaan"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Siirry edelliseen"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Muuta kokoa"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Puhelin sammui kuumuuden takia"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Puhelimesi toimii nyt normaalisti."</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Puhelimesi toimii nyt normaalisti.\nLue lisää napauttamalla"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Puhelimesi oli liian kuuma, joten se sammui. Puhelimesi toimii nyt normaalisti.\n\nPuhelimesi voi kuumentua liikaa, jos\n • käytät paljon resursseja vaativia sovelluksia (esim. pelejä, videoita tai navigointisovelluksia)\n • lataat tai lähetät suuria tiedostoja\n • käytät puhelintasi korkeissa lämpötiloissa."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Katso huoltovaiheet"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Puhelin lämpenee"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana."</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Joidenkin ominaisuuksien käyttöä on rajoitettu puhelimen jäähtymisen aikana.\nLue lisää napauttamalla"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Puhelimesi yrittää automaattisesti jäähdyttää itsensä. Voit silti käyttää puhelinta, mutta se voi toimia hitaammin.\n\nKun puhelin on jäähtynyt, se toimii normaalisti."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Katso huoltovaiheet"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Irrota laturi"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Laitetta ladattaessa tapahtui virhe. Irrota virtalähde varovasti – johto voi olla lämmin."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Katso huoltovaiheet"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f58d1aa7b7dd..15cf6eb40658 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Développer"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Réduire"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Fermer"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Paramètres"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Faire glisser vers le bas pour ignorer"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> est en mode d\'incrustation d\'image"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Si vous ne voulez pas que <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, touchez l\'écran pour ouvrir les paramètres, puis désactivez-la."</string>
- <string name="pip_play" msgid="333995977693142810">"Lire"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Interrompre"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Passer au suivant"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Revenir au précédent"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionner"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Tél. éteint car il surchauffait"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Votre téléphone fonctionne maintenant normalement"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Votre téléphone fonctionne maintenant de manière normale.\nTouchez pour en savoir plus"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Votre téléphone s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • Util. des applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.)\n • Téléchargez ou téléversez de gros fichiers\n • Utilisez téléphone dans des températures élevées"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Le téléphone commence à chauffer"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Les fonctionnalités sont limitées pendant que le téléphone refroidit"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Certaines fonctionnalités sont limitées pendant que le téléphone refroidit.\nTouchez pour en savoir plus"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Débranchez le chargeur"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Il y a un problème avec la recharge de cet appareil. Débranchez l\'adaptateur d\'alimentation, et faites attention, car le câble pourrait être chaud."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index ed9a5dd11ad7..784186b013a9 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifier l\'ordre des paramètres."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> sur <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Écran de verrouillage"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Développer"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Réduire"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Fermer"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Paramètres"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Faire glisser vers le bas pour ignorer"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> est en mode Picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Si vous ne voulez pas que l\'application <xliff:g id="NAME">%s</xliff:g> utilise cette fonctionnalité, appuyez ici pour ouvrir les paramètres et la désactiver."</string>
- <string name="pip_play" msgid="333995977693142810">"Lecture"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Suspendre"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Passer au contenu suivant"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Passer au contenu précédent"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionner"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Tél. éteint car il surchauffait"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"À présent, votre téléphone fonctionne normalement"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"À présent, votre téléphone fonctionne normalement.\nAppuyer pour en savoir plus"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Votre téléphone s\'est éteint, car il surchauffait. Il s\'est refroidi et fonctionne normalement.\n\nIl peut surchauffer si vous :\n • exécutez applis utilisant beaucoup de ressources (jeux, vidéo, navigation, etc.) ;\n • téléchargez ou importez gros fichiers ;\n • utilisez téléphone à des températures élevées."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Le téléphone chauffe"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Fonctionnalités limitées pendant le refroidissement du téléphone"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Fonctionnalités limitées pendant le refroidissement du téléphone.\nAppuyer pour en savoir plus"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Votre téléphone va essayer de se refroidir automatiquement. Vous pouvez toujours l\'utiliser, mais il risque d\'être plus lent.\n\nUne fois refroidi, il fonctionnera normalement."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Afficher les étapes d\'entretien"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Débrancher le chargeur"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Un problème est survenu lors de la recharge de cet appareil. Débranchez l\'adaptateur secteur en faisant attention, car le câble risque d\'être chaud."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Afficher les étapes d\'entretien"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 33e30e0b8164..c732c7bbff1f 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar a orde das opcións de configuración."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Páxina <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Pantalla de bloqueo"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Despregar"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Pechar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Configuración"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrastra cara abaixo para ignorar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menú"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> está na pantalla superposta"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se non queres que <xliff:g id="NAME">%s</xliff:g> utilice esta función, toca a configuración para abrir as opcións e desactivar a función."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproducir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Ir ao seguinte"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Ir ao anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Cambiar tamaño"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"O teléfono apagouse pola calor"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"O teu teléfono funciona agora con normalidade"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"O teléfono funciona con normalidade.\nToca para obter máis información"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O teléfono estaba moi quente, apagouse para que arrefríe e agora funciona con normalidade.\n\nÉ posible que estea moi quente se:\n • Usas aplicacións que requiren moitos recursos (como aplicacións de navegación, vídeos e xogos)\n • Descargas/cargas ficheiros grandes\n • Usas o teléfono a alta temperatura"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver pasos de mantemento"</string>
<string name="high_temp_title" msgid="2218333576838496100">"O teléfono está quentando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"O uso dalgunhas funcións é limitado mentres o teléfono arrefría.\nToca para obter máis información"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"O teléfono tentará arrefriar automaticamente. Podes utilizalo, pero é probable que funcione máis lento.\n\nUnha vez que arrefríe, funcionará con normalidade."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver pasos de mantemento"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecta o cargador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Produciuse un problema ao cargar este dispositivo. Desconecta o adaptador de corrente e ten coidado porque o cable pode estar quente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver pasos de mantemento"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5c91a1743ed6..6860c28eb276 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="4811759950673118541">"સિસ્ટમ UI"</string>
<string name="status_bar_clear_all_button" msgid="2491321682873657397">"સાફ કરો"</string>
- <string name="status_bar_no_notifications_title" msgid="7812479124981107507">"કોઈ સૂચનાઓ નથી"</string>
+ <string name="status_bar_no_notifications_title" msgid="7812479124981107507">"કોઈ નોટિફિકેશન નથી"</string>
<string name="status_bar_ongoing_events_title" msgid="3986169317496615446">"ચાલુ"</string>
<string name="status_bar_latest_events_title" msgid="202755896454005436">"નોટિફિકેશનો"</string>
<string name="battery_low_title" msgid="6891106956328275225">"બૅટરી ટૂંક સમયમાં સમાપ્ત થશે"</string>
@@ -368,7 +368,7 @@
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"સ્થાન બંધ"</string>
<string name="quick_settings_media_device_label" msgid="8034019242363789941">"મીડિયા ઉપકરણ"</string>
<string name="quick_settings_rssi_label" msgid="3397615415140356701">"RSSI"</string>
- <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ફક્ત કટોકટીના કૉલ્સ"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="7499207215265078598">"ફક્ત ઇમર્જન્સી કૉલ"</string>
<string name="quick_settings_settings_label" msgid="2214639529565474534">"સેટિંગ"</string>
<string name="quick_settings_time_label" msgid="3352680970557509303">"સમય"</string>
<string name="quick_settings_user_label" msgid="1253515509432672496">"હું"</string>
@@ -517,7 +517,7 @@
<string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"બધા સાઇલન્ટ નોટિફિકેશન સાફ કરો"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ખલેલ પાડશો નહીં દ્વારા થોભાવેલ નોટિફિકેશન"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"હવે પ્રારંભ કરો"</string>
- <string name="empty_shade_text" msgid="8935967157319717412">"કોઈ સૂચનાઓ નથી"</string>
+ <string name="empty_shade_text" msgid="8935967157319717412">"કોઈ નોટિફિકેશન નથી"</string>
<string name="profile_owned_footer" msgid="2756770645766113964">"પ્રોફાઇલ મૉનિટર કરી શકાય છે"</string>
<string name="vpn_footer" msgid="3457155078010607471">"નેટવર્ક મૉનિટર કરી શકાય છે"</string>
<string name="branded_vpn_footer" msgid="816930186313188514">"નેટવર્ક મૉનિટર કરવામાં આવી શકે છે"</string>
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"સેટિંગ્સનો ક્રમ સંપાદિત કરો."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> માંથી <xliff:g id="ID_1">%1$d</xliff:g> પૃષ્ઠ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"લૉક સ્ક્રીન"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"વિસ્તૃત કરો"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"નાનું કરો"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"બંધ કરો"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"સેટિંગ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"છોડી દેવા માટે નીચે ખેંચો"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"મેનૂ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ચિત્રમાં-ચિત્રની અંદર છે"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"જો તમે નથી ઇચ્છતા કે <xliff:g id="NAME">%s</xliff:g> આ સુવિધાનો ઉપયોગ કરે, તો સેટિંગ ખોલવા માટે ટૅપ કરો અને તેને બંધ કરો."</string>
- <string name="pip_play" msgid="333995977693142810">"ચલાવો"</string>
- <string name="pip_pause" msgid="1139598607050555845">"થોભાવો"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"આગલા પર જાઓ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"પહેલાંના પર જાઓ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"કદ બદલો"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ફોન વધુ પડતી ગરમીને લીધે બંધ થઇ ગયો છે"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"તમારો ફોન અત્યંત ગરમ હતો, તેથી તે ઠંડો થવા આપમેળે બંધ થઇ ગયો છે. તમારો ફોન હવે સામાન્યપણે કાર્ય કરી રહ્યો છે.\n\nતમારો ફોન અત્યંત ગરમ થઇ શકે છે, જો તમે:\n • એવી ઍપ્લિકેશન વાપરતા હો જે સંસાધન સઘન રીતે વાપરતી હોય (જેમ કે ગેમિંગ, વીડિઓ, અથવા નેવિગેટ કરતી ઍપ્લિકેશનો)\n • મોટી ફાઇલો અપલોડ અથવા ડાઉનલોડ કરતા હો\n • તમારા ફોનનો ઉપયોગ ઉચ્ચ તાપમાનમાં કરતા હો"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ફોન ગરમ થઈ રહ્યો છે"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ફોન ઠંડો થાય ત્યાં સુધી કેટલીક સુવિધાઓ મર્યાદિત હોય છે"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"તમારો ફોન આપમેળે ઠંડો થવાનો પ્રયાસ કરશે. તમે હજી પણ તમારા ફોનનો ઉપયોગ કરી શકો છો, પરંતુ તે કદાચ થોડો ધીમો ચાલે.\n\nતમારો ફોન ઠંડો થઈ જવા પર, તે સામાન્ય રીતે ચાલશે."</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ચાર્જરને અનપ્લગ કરો"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"આ ડિવાઇસને ચાર્જ કરવામાં કોઈ સમસ્યા છે. પાવર અડૅપ્ટર અનપ્લગ કરો અને કાળજી લેજો કદાચ કેબલ થોડો ગરમ થયો હોઈ શકે છે."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"સારસંભાળના પગલાં જુઓ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index bdd2052f6aa6..2b8c9832d7f8 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -918,25 +918,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिंग के क्रम को बदलें"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"पेज <xliff:g id="ID_2">%2$d</xliff:g> में से <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्‍क्रीन"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"विस्तार करें"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"छोटा करें"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"बंद करें"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"सेटिंग"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"खारिज करने के लिए नीचे खींचें और छोड़ें"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"मेन्यू"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> \"पिक्चर में पिक्चर\" के अंदर है"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"अगर आप नहीं चाहते कि <xliff:g id="NAME">%s</xliff:g> इस सुविधा का उपयोग करे, तो सेटिंग खोलने के लिए टैप करें और उसे बंद करें ."</string>
- <string name="pip_play" msgid="333995977693142810">"चलाएं"</string>
- <string name="pip_pause" msgid="1139598607050555845">"रोकें"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"अगले पर जाएं"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"पिछले पर जाएं"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"आकार बदलें"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"गर्म होने की वजह से फ़ोन बंद हुआ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"आपका फ़ोन अब सामान्य रूप से चल रहा है"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"आपका फ़ोन सामान्य रूप से काम कर रहा है.\nज़्यादा जानकारी के लिए टैप करें"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"फ़ोन बहुत गर्म हो गया था, इसलिए ठंडा होने के लिए बंद हो गया. फ़ोन अब अच्छे से चल रहा है.\n\nफ़ोन तब बहुत गर्म हो सकता है जब आप:\n • ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाते हैं (जैसे गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन)\n • बड़ी फ़ाइलें डाउनलोड या अपलोड करते हैं\n • ज़्यादा तापमान में फ़ोन का इस्तेमाल करते हैं"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"डिवाइस के रखरखाव के तरीके देखें"</string>
<string name="high_temp_title" msgid="2218333576838496100">"फ़ोन गर्म हो रहा है"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"फ़ोन के ठंडा होने के दौरान कुछ सुविधाएं सीमित होती हैं"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"फ़ोन के ठंडा होने तक कुछ सुविधाएं काम नहीं करतीं.\nज़्यादा जानकारी के लिए टैप करें"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अब भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"डिवाइस के रखरखाव के तरीके देखें"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर निकालें"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"इस डिवाइस को चार्ज करने में समस्या हुई. पावर अडैप्टर का प्लग निकालें. ऐसा करते समय सावधानी बरतें क्योंकि तार गर्म हो सकता है."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"प्रबंधन से जुड़े चरण देखें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 22444c2ccb3f..bfd5aa001c24 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Uređivanje redoslijeda postavki."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Zaključan zaslon"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Proširivanje"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimiziraj"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zatvori"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Postavke"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Povucite prema dolje da biste odbacili"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Izbornik"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> jest na slici u slici"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ako ne želite da aplikacija <xliff:g id="NAME">%s</xliff:g> upotrebljava tu značajku, dodirnite da biste otvorili postavke i isključili je."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproduciraj"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pauziraj"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Preskoči na sljedeće"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Preskoči na prethodno"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Promjena veličine"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon se isključio zbog vrućine"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon sada radi normalno"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon sad radi normalno.\nDodirnite za više informacija"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon se pregrijao, stoga se isključio kako bi se ohladio Telefon sada radi normalno.\n\nTelefon se može pregrijati ako:\n • upotrebljavate zahtjevne aplikacije (kao što su igre, aplikacije za videozapise ili navigaciju)\n • preuzimate ili prenosite velike datoteke\n • upotrebljavate telefon na visokim temperaturama."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Pročitajte upute za održavanje"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon se zagrijava"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Neke su značajke ograničene dok se telefon hladi"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Neke su značajke ograničene dok se telefon ne ohladi.\nDodirnite za više informacija"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon će se automatski pokušati ohladiti. Možete ga nastaviti koristiti, no mogao bi raditi sporije.\n\nKad se ohladi, radit će normalno."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Pročitajte upute za održavanje"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Iskopčajte punjač"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pojavio se problem s punjenjem uređaja. Iskopčajte pretvarač napona i pazite jer se kabel može zagrijati."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Pogledajte upute za održavanje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index ef49fa58d594..c8f4a467f94b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Beállítások sorrendjének szerkesztése."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. oldal, összesen: <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lezárási képernyő"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Kibontás"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Kis méret"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Bezárás"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Beállítások"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Elvetéshez húzza lefelé"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menü"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"A(z) <xliff:g id="NAME">%s</xliff:g> kép a képben funkciót használ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ha nem szeretné, hogy a(z) <xliff:g id="NAME">%s</xliff:g> használja ezt a funkciót, koppintson a beállítások megnyitásához, és kapcsolja ki."</string>
- <string name="pip_play" msgid="333995977693142810">"Lejátszás"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Szüneteltetés"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Ugrás a következőre"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Ugrás az előzőre"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Átméretezés"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"A meleg miatt kikapcsolt"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"A telefon most már megfelelően működik"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonja most már megfelelően működik.\nKoppintson, ha további információra van szüksége."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonja túlmelegedett, így kikapcsolt, hogy lehűlhessen. Most már megfelelően működik.\n\nA telefon akkor melegedhet túl, ha Ön:\n • Energiaigényes alkalmazásokat használ (például játékokat, videókat vagy navigációs alkalmazásokat)\n • Nagy fájlokat tölt le vagy fel\n • Melegben használja a telefonját"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Olvassa el a kímélő használat lépéseit"</string>
<string name="high_temp_title" msgid="2218333576838496100">"A telefon melegszik"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Bizonyos funkciók korlátozottan működnek a telefon hűlése közben"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Bizonyos funkciók korlátozottan működnek a telefon lehűlése közben.\nKoppintson, ha további információra van szüksége."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"A telefon automatikusan megpróbál lehűlni. Továbbra is tudja használni a telefont, de elképzelhető, hogy működése lelassul.\n\nAmint a telefon lehűl, újra a szokásos módon működik majd."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Olvassa el a kímélő használat lépéseit"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Húzza ki a töltőt"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Probléma adódott az eszköz töltése során. Húzza ki a hálózati adaptert. Vigyázzon, a kábel forró lehet."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Olvassa el a megfelelő használat lépéseit"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 15e45986a5cc..53286188af47 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Խմբագրել կարգավորումների հերթականությունը:"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Ընդարձակել"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Ծալել"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Փակել"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Կարգավորումներ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Քաշեք վար՝ փակելու համար"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Ընտրացանկ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g>-ը «Նկար նկարի մեջ» ռեժիմում է"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Եթե չեք ցանկանում, որ <xliff:g id="NAME">%s</xliff:g>-ն օգտագործի այս գործառույթը, հպեք՝ կարգավորումները բացելու և այն անջատելու համար։"</string>
- <string name="pip_play" msgid="333995977693142810">"Նվագարկել"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Դադարեցնել"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Անցնել հաջորդին"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Վերադառնալ նախորդին"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Փոխել չափը"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել է տաքանալու պատճառով"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Հեռախոսն այժմ նորմալ աշխատում է"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Հեռախոսն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար։"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավարկման հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Հեռախոսը տաքանում է"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Հովանալու ընթացքում հեռախոսի որոշ գործառույթներ սահմանափակ են։\nՀպեք՝ ավելին իմանալու համար։"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ձեր հեռախոսն ավտոմատ կերպով կփորձի hովանալ: Կարող եք շարունակել օգտագործել հեռախոսը, սակայն հնարավոր է, որ այն ավելի դանդաղ աշխատի:\n\nՀովանալուց հետո հեռախոսը կաշխատի կանոնավոր կերպով:"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Անջատեք լիցքավորիչը հոսանքից"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Չհաջողվեց լիցքավորել սարքը: Անջատեք հոսանքի ադապտերը և ուշադիր եղեք՝ մալուխը կարող է տաքացած լինել:"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c1c554b566c9..dfed57b94c51 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit urutan setelan."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> dari <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Layar kunci"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Luaskan"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimalkan"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Tutup"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Setelan"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Tarik ke bawah untuk menutup"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> adalah picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
- <string name="pip_play" msgid="333995977693142810">"Putar"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Jeda"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Lewati ke berikutnya"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Lewati ke sebelumnya"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ubah ukuran"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Ponsel dimatikan karena panas"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Ponsel kini berfungsi normal"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ponsel kini berfungsi normal.\nKetuk untuk info selengkapnya"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ponsel menjadi terlalu panas, jadi dimatikan untuk mendinginkan. Ponsel kini berfungsi normal.\n\nPonsel dapat menjadi terlalu panas jika Anda:\n • Menggunakan aplikasi yang menggunakan sumber daya secara intensif (seperti aplikasi game, video, atau navigasi)\n • Mendownload atau mengupload file besar\n • Menggunakan ponsel dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah-langkah perawatan"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Ponsel menjadi hangat"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Beberapa fitur dibatasi saat ponsel mendingin"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Beberapa fitur dibatasi saat ponsel mendingin.\nKetuk untuk info selengkapnya"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ponsel akan otomatis mencoba mendingin. Anda tetap dapat menggunakan ponsel, tetapi mungkin berjalan lebih lambat.\n\nSetelah dingin, ponsel akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah-langkah perawatan"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut pengisi daya"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ada masalah saat mengisi daya perangkat ini. Cabut adaptor daya dan berhati-hatilah karena kabelnya mungkin panas."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah-langkah perawatan"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9d0c2b464ef0..57cdb272f176 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Breyta röð stillinga."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Blaðsíða <xliff:g id="ID_1">%1$d</xliff:g> af <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lásskjár"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Stækka"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minnka"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Loka"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Stillingar"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Draga niður til að hunsa"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Valmynd"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> er með mynd í mynd"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ef þú vilt ekki að <xliff:g id="NAME">%s</xliff:g> noti þennan eiginleika skaltu ýta til að opna stillingarnar og slökkva á því."</string>
- <string name="pip_play" msgid="333995977693142810">"Spila"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Gera hlé"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Fara á næsta"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Fara á fyrra"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Breyta stærð"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Slökkt var á símanum vegna hita"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Síminn virkar núna sem skyldi"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Síminn virkar nú eins og venjulega.\nÝttu til að fá frekari upplýsingar"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Síminn varð of heitur og því var slökkt á honum til að kæla hann. Síminn virkar núna sem skyldi.\n\nSíminn getur orðið of heitur ef þú:\n • Notar plássfrek forrit (t.d. leikja-, myndbands- eða leiðsagnarforrit\n • Sækir eða hleður upp stórum skrám\n • Notar símann í miklum hita"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Sjá varúðarskref"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Síminn er að hitna"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Sumir eiginleikar eru takmarkaðir þegar síminn kælir sig"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Sumir eiginleikar eru takmarkaðir meðan síminn kælir sig.\nÝttu til að fá frekari upplýsingar"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Síminn reynir sjálfkrafa að kæla sig. Þú getur enn notað símann en hann gæti verið hægvirkari.\n\nEftir að síminn hefur kælt sig niður virkar hann eðlilega."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Sjá varúðarskref"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Taktu hleðslutækið úr sambandi"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Upp kom vandamál varðandi hleðslu tækisins. Taktu straumbreytinn úr sambandi og farðu varlega því snúran gæti verið heit."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Sjá varúðarskref"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 749ce6d1cc50..679eb551e7f0 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifica l\'ordine delle impostazioni."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> di <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Schermata di blocco"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Espandi"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Riduci a icona"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Chiudi"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Impostazioni"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Trascina verso il basso per ignorare"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> è in Picture in picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se non desideri che l\'app <xliff:g id="NAME">%s</xliff:g> utilizzi questa funzione, tocca per aprire le impostazioni e disattivarla."</string>
- <string name="pip_play" msgid="333995977693142810">"Riproduci"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Metti in pausa"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Passa ai contenuti successivi"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Passa ai contenuti precedenti"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ridimensiona"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Il telefono si è spento perché surriscaldato"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Ora il telefono funziona normalmente"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ora il telefono funziona normalmente.\nTocca per ulteriori informazioni"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Il telefono era surriscaldato e si è spento per raffreddarsi. Ora funziona normalmente.\n\nIl telefono può surriscaldarsi se:\n • Utilizzi app che consumano molte risorse (ad esempio app di navigazione, giochi o video)\n • Scarichi o carichi grandi file\n • Lo utilizzi in presenza di alte temperature"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Leggi le misure da adottare"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Il telefono si sta scaldando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Alcune funzioni limitate durante il raffreddamento del telefono"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Alcune funzionalità limitate durante il raffreddamento del telefono.\nTocca per ulteriori informazioni"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Il telefono cercherà automaticamente di raffreddarsi. Puoi comunque usarlo, ma potrebbe essere più lento.\n\nUna volta raffreddato, il telefono funzionerà normalmente."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Leggi le misure da adottare"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Scollega il caricabatterie"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Si è verificato un problema durante la ricarica del dispositivo. Scollega l\'alimentatore e presta attenzione perché il cavo potrebbe essere caldo."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Leggi le misure da adottare"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c2f0a9f2f8e3..b6a723f00024 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"עריכת סדר ההגדרות."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"דף <xliff:g id="ID_1">%1$d</xliff:g> מתוך <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"מסך נעילה"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"הרחב"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"מזער"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"סגור"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"הגדרות"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"גרור למטה כדי לסגור"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"תפריט"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> במצב תמונה בתוך תמונה"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"אם אינך רוצה שהתכונה הזו תשמש את <xliff:g id="NAME">%s</xliff:g>, יש להקיש כדי לפתוח את ההגדרות ולכבות את התכונה."</string>
- <string name="pip_play" msgid="333995977693142810">"הפעל"</string>
- <string name="pip_pause" msgid="1139598607050555845">"השהה"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"אפשר לדלג אל הבא"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"אפשר לדלג אל הקודם"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"שינוי גודל"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"הטלפון כבה עקב התחממות"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"הטלפון פועל כרגיל עכשיו"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"הטלפון פועל כרגיל עכשיו.\nיש להקיש כדי להציג מידע נוסף"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"הטלפון שלך התחמם יותר מדי וכבה כדי להתקרר. הטלפון פועל כרגיל עכשיו.\n\nייתכן שהטלפון יתחמם יותר מדי אם:\n • תשתמש באפליקציות עתירות משאבים (כגון משחקים, אפליקציות וידאו או אפליקציות ניווט)\n • תוריד או תעלה קבצים גדולים\n • תשתמש בטלפון בטמפרטורות גבוהות"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"לצפייה בשלבי הטיפול"</string>
<string name="high_temp_title" msgid="2218333576838496100">"הטלפון מתחמם"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"חלק מהתכונות מוגבלות כל עוד הטלפון מתקרר.\nיש להקיש כדי להציג מידע נוסף"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"קירור הטלפון ייעשה באופן אוטומטי. תוכל עדיין להשתמש בטלפון, אבל ייתכן שהוא יפעל לאט יותר.\n\nהטלפון יחזור לפעול כרגיל לאחר שיתקרר."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"לצפייה בשלבי הטיפול"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"יש לנתק את המטען"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"יש בעיה עם טעינת מכשיר זה. יש לנתק את מתאם המתח בזהירות כיוון שייתכן שהכבל חם."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"לצפייה בשלבי הטיפול"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index f33ac282b99d..b70e2e2bc14f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"設定の順序を編集します。"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ページ <xliff:g id="ID_1">%1$d</xliff:g>/<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ロック画面"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"展開"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"最小化"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"閉じる"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"設定"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"下にドラッグして閉じる"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"メニュー"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g>はピクチャー イン ピクチャーで表示中です"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g>でこの機能を使用しない場合は、タップして設定を開いて OFF にしてください。"</string>
- <string name="pip_play" msgid="333995977693142810">"再生"</string>
- <string name="pip_pause" msgid="1139598607050555845">"一時停止"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"次へスキップ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"前へスキップ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"サイズ変更"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"高熱で電源が OFF になりました"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"お使いのスマートフォンは現在、正常に動作しています"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"お使いのスマートフォンは現在、正常に動作しています。\nタップして詳細を表示"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"スマートフォンが熱すぎたため電源が OFF になりました。現在は正常に動作しています。\n\nスマートフォンは以下の場合に熱くなる場合があります。\n • リソースを集中的に使用する機能やアプリ(ゲームアプリ、動画アプリ、ナビアプリなど)を使用\n • サイズの大きいファイルをダウンロードまたはアップロード\n • 高温の場所で使用"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"取り扱いに関する手順をご覧ください"</string>
<string name="high_temp_title" msgid="2218333576838496100">"スマートフォンの温度が上昇中"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"スマートフォンのクールダウン中は一部の機能が制限されます"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"スマートフォンのクールダウン中は一部の機能が制限されます。\nタップして詳細を表示"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"スマートフォンは自動的にクールダウンを行います。その間もスマートフォンを使用できますが、動作が遅くなる可能性があります。\n\nクールダウンが完了すると、通常どおり動作します。"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"取り扱いに関する手順をご覧ください"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"充電器を電源から外してください"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"このデバイスの充電中に問題が発生しました。電源アダプターを電源から外してください。ケーブルが熱くなっている可能性がありますのでご注意ください。"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"取り扱いに関する手順をご覧ください"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 7dcc7a6d5030..0dda483b9d16 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"პარამეტრების მიმდევრობის რედაქტირება."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"გვერდი <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>-დან"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ჩაკეტილი ეკრანი"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"გაშლა"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ჩაკეცვა"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"დახურვა"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"პარამეტრები"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"დასახურად ჩავლებით ჩამოიტანეთ ქვემოთ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"მენიუ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> იყენებს რეჟიმს „ეკრანი ეკრანში“"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"თუ არ გსურთ, რომ <xliff:g id="NAME">%s</xliff:g> ამ ფუნქციას იყენებდეს, აქ შეხებით შეგიძლიათ გახსნათ პარამეტრები და გამორთოთ ის."</string>
- <string name="pip_play" msgid="333995977693142810">"დაკვრა"</string>
- <string name="pip_pause" msgid="1139598607050555845">"დაპაუზება"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"შემდეგზე გადასვლა"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"წინაზე გადასვლა"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ზომის შეცვლა"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ტელეფონი გამოირთო გაცხელების გამო"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"თქვენი ტელეფონი ახლა ჩვეულებრივად მუშაობს"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"თქვენი ტელეფონი უკვე ნორმალურად მუშაობს.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"თქვენი ტელეფონი გამოირთო გასაგრილებლად, რადგან ის მეტისმეტად გაცხელდა. ახლა ის ჩვეულებრივად მუშაობს.\n\nტელეფონის გაცხელების მიზეზებია:\n • რესურსტევადი აპების გამოყენება (მაგ. სათამაშო, ვიდეო ან ნავიგაციის აპების)\n • დიდი ფაილების ჩამოტვირთვა ან ატვირთვა\n • ტელეფონის გამოყენება მაღალი ტემპერატურისას"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"მისაღები ზომების გაცნობა"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ტელეფონი ცხელდება"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ზოგიერთი ფუნქცია შეზღუდული იქნება, სანამ ტელეფონი გაგრილდება.\nშეეხეთ დამატებითი ინფორმაციის მისაღებად"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"თქვენი ტელეფონი გაგრილებას ავტომატურად შეეცდება. შეგიძლიათ გააგრძელოთ მისით სარგებლობა, თუმცა ტელეფონმა შეიძლება უფრო ნელა იმუშაოს.\n\nგაგრილების შემდგომ ის ჩვეულებრივად იმუშავებს."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"მისაღები ზომების გაცნობა"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"გამოაერთეთ დამტენი"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ამ მოწყობილობის დატენა ვერ ხერხდება პრობლემის გამო. გამოაერთეთ ელკვების ადაპტერი და გამოიჩინეთ სიფრთხილე, რადგან კაბელი შეიძლებოდა გაცხელებულიყო."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"მისაღები ზომების გაცნობა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index a6dbec3a2b48..8e10230f2212 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Параметрлер тәртібін өзгерту."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ішінен <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Құлыпталған экран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Жаю"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Кішірейту"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Жабу"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Параметрлер"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Жабу үшін төмен қарай сүйреңіз"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Mәзір"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> \"суреттегі сурет\" режимінде"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> деген пайдаланушының бұл мүмкіндікті пайдалануын қаламасаңыз, параметрлерді түртіп ашыңыз да, оларды өшіріңіз."</string>
- <string name="pip_play" msgid="333995977693142810">"Ойнату"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Кідірту"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Келесіге өту"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Алдыңғысына оралу"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Өлшемін өзгерту"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон қызып кеткендіктен өшірілді"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Телефоныңыз қазір қалыпты жұмыс істеп тұр"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефоныңыз қалыпты жұмыс істеп тұр.\nТолығырақ ақпарат алу үшін түртіңіз."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефоныңыз қатты қызып кеткендіктен өшірілді. Телефоныңыз қазір қалыпты жұмыс істеп тұр.\n\nТелефоныңыз мына жағдайларда ыстық болуы мүмкін:\n • Ресурстар талап ететін қолданбаларды пайдалану (ойын, бейне немесе навигация қолданбалары)\n • Үлкен көлемді файлдарды жүктеу немесе жүктеп салу\n • Телефонды жоғары температурада пайдалану"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Пайдалану нұсқаулығын қараңыз"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефон қызуда"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон толық суығанға дейін, кейбір функциялардың жұмысы шектеледі.\nТолығырақ ақпарат үшін түртіңіз."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон автоматты түрде суи бастайды. Оны пайдалана бере аласыз, бірақ ол баяуырақ жұмыс істеуі мүмкін.\n\nТелефон суығаннан кейін, оның жұмысы қалпына келеді."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Пайдалану нұсқаулығын қараңыз"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Зарядтағышты ажыратыңыз"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Құрылғыны зарядтау кезінде ақау шықты. Қуат адаптерін ажыратыңыз. Кабель ыстық болуы мүмкін, абай болыңыз."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Пайдалану нұсқаулығын қараңыз"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index f2774e4ab305..7410ddded885 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"កែលំដាប់ការកំណត់"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ទំព័រ <xliff:g id="ID_1">%1$d</xliff:g> នៃ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"អេក្រង់​ចាក់សោ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ពង្រីក"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"បង្រួម"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"បិទ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ការកំណត់"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"អូស​ចុះក្រោម​ដើម្បី​បដិសេធ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ម៉ឺនុយ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ស្ថិតក្នុងមុខងាររូបក្នុងរូប"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"ប្រសិនបើ​អ្នក​មិន​ចង់​ឲ្យ <xliff:g id="NAME">%s</xliff:g> ប្រើ​មុខងារ​នេះ​ សូមចុច​​បើក​ការកំណត់ រួច​បិទ​វា។"</string>
- <string name="pip_play" msgid="333995977693142810">"លេង"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ផ្អាក"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"រំលងទៅបន្ទាប់"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"រំលងទៅក្រោយ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ប្ដូរ​ទំហំ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ទូរសព្ទ​បាន​បិទដោយសារ​វា​ឡើងកម្តៅ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ឥឡូវនេះ​ទូរសព្ទ​របស់អ្នក​កំពុង​ដំណើរការ​ធម្មតា"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ទូរសព្ទ​របស់អ្នក​ក្តៅពេក ដូច្នេះ​វាបាន​បិទ​ដើម្បី​បន្ថយ​កម្តៅ។ ឥឡូវនេះ ​ទូរសព្ទ​របស់អ្នក​កំពុង​ដំណើរការ​ធម្មតា។\n\nទូរសព្ទ​របស់អ្នក​អាចនឹង​ឡើង​កម្តៅ​ខ្លាំងជ្រុល ប្រសិន​បើអ្នក៖\n • ប្រើប្រាស់​កម្មវិធី​ដែល​ប្រើប្រាស់ទិន្នន័យច្រើនក្នុងរយៈពេលខ្លី (ដូចជាហ្គេម វីដេអូ ឬកម្មវិធីរុករក)\n • ទាញយក ឬ​បង្ហោះ​ឯកសារដែលមានទំហំធំ\n • ប្រើប្រាស់​ទូរសព្ទ​របស់អ្នក​នៅកន្លែង​មានសីតុណ្ហភាព​ខ្ពស់"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ទូរសព្ទ​នេះ​កំពុង​កើន​កម្តៅ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"មុខងារ​មួយ​ចំនួន​នឹង​មិន​អាច​ប្រើ​បាន​ពេញលេញ​នោះ​ទេ ខណៈពេល​ដែល​ទូរសព្ទ​កំពុង​បញ្ចុះ​កម្តៅ"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ទូរសព្ទ​របស់អ្នក​នឹង​ព្យាយាម​បញ្ចុះ​កម្តៅ​ដោយ​ស្វ័យប្រវត្តិ។ អ្នក​នៅតែ​អាច​ប្រើ​ទូរសព្ទ​របស់អ្នក​បាន​ដដែល​ ប៉ុន្តែ​វា​នឹង​ដំណើរ​ការ​យឺត​ជាង​មុន។\n\nបន្ទាប់​ពី​ទូរសព្ទ​របស់អ្នក​ត្រជាក់​ជាង​មុន​ហើយ វា​នឹង​ដំណើរការ​ដូច​ធម្មតា។"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ផ្ដាច់ឆ្នាំងសាក"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"មាន​បញ្ហា​ក្នុងការសាកថ្ម​ឧបករណ៍​នេះ។ សូមផ្ដាច់​ឆ្នាំងសាក ហើយ​ប្រុងប្រយ័ត្ន ដោយសារ​ខ្សែ​អាចមាន​កម្ដៅ​ក្ដៅ។"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"មើលជំហាន​ថែទាំ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 1f4d90326acd..2034472d18cd 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಕ್ರಮವನ್ನು ಎಡಿಟ್ ಮಾಡಿ."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="ID_1">%1$d</xliff:g> ಪುಟ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ಲಾಕ್ ಪರದೆ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ವಿಸ್ತೃತಗೊಳಿಸು"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ಕುಗ್ಗಿಸಿ"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ಮುಚ್ಚಿ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ವಜಾಗೊಳಿಸಲು ಕೆಳಕ್ಕೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ಮೆನು"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವಾಗಿದೆ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ಈ ವೈಶಿಷ್ಟ್ಯ ಬಳಸುವುದನ್ನು ನೀವು ಬಯಸದಿದ್ದರೆ, ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೆರೆಯಲು ಮತ್ತು ಅದನ್ನು ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="pip_play" msgid="333995977693142810">"ಪ್ಲೇ"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ವಿರಾಮಗೊಳಿಸಿ"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ಮುಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ಹಿಂದಕ್ಕೆ ಸ್ಕಿಪ್‌ ಮಾಡಿ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ಮರುಗಾತ್ರಗೊಳಿಸಿ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ಫೋನ್ ಬಿಸಿಯಾಗಿದ್ದರಿಂದ ಆಫ್ ಆಗಿದೆ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ಈಗ ನಿಮ್ಮ ಫೋನ್ ಎಂದಿನಂತೆ ಕೆಲಸ ಮಾಡುತ್ತಿದೆ"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"ನಿಮ್ಮ ಫೋನ್ ಈಗ ಎಂದಿನಂತೆ ರನ್ ಆಗುತ್ತಿದೆ.\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ನಿಮ್ಮ ಫೋನ್ ತುಂಬಾ ಬಿಸಿಯಾಗಿತ್ತು, ತಣ್ಣಗಾಗಲು ಅದು ತಾನಾಗಿ ಆಫ್ ಆಗಿದೆ. ಈಗ ನಿಮ್ಮ ಫೋನ್ ಎಂದಿನಂತೆ ಕೆಲಸ ಮಾಡುತ್ತಿದೆ.\n\nನಿಮ್ಮ ಫೋನ್ ಬಿಸಿಯಾಗಲು ಕಾರಣಗಳು:\n • ಹೆಚ್ಚು ಸಂಪನ್ಮೂಲ ಉಪಯೋಗಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಬಳಕೆ (ಉದಾ, ಗೇಮಿಂಗ್, ವೀಡಿಯೊ/ನ್ಯಾವಿಗೇಶನ್ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು)\n • ದೊಡ್ಡ ಫೈಲ್‌ಗಳ ಡೌನ್‌ಲೋಡ್ ಅಥವಾ ಅಪ್‌ಲೋಡ್\n • ಅಧಿಕ ಉಷ್ಣಾಂಶದಲ್ಲಿ ಫೋನಿನ ಬಳಕೆ"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ಫೋನ್ ಬಿಸಿಯಾಗುತ್ತಿದೆ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸುತ್ತದೆ"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ಫೋನ್ ತಣ್ಣಗಾಗುವವರೆಗೂ ಕೆಲವು ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಸೀಮಿತಗೊಳಿಸಲಾಗುತ್ತದೆ\nಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ನಿಮ್ಮ ಫೋನ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ತಣ್ಣಗಾಗಲು ಪ್ರಯತ್ನಿಸುತ್ತದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ನೀವು ಈಗಲೂ ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ, ಆದರೆ ಇದು ನಿಧಾನವಾಗಿರಬಹುದು.\n\nಒಮ್ಮೆ ನಿಮ್ಮ ಫೋನ್ ತಣ್ಣಗಾದ ನಂತರ ಇದು ಸಾಮಾನ್ಯ ರೀತಿಯಲ್ಲಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ಕಾಳಜಿಯ ಹಂತಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ಚಾರ್ಜರ್ ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ಈ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡುತ್ತಿರುವಾಗ ಸಮಸ್ಯೆ ಎದುರಾಗಿದೆ. ಪವರ್ ಅಡಾಪ್ಟರ್ ಅನ್ನು ಅನ್‌ಪ್ಲಗ್ ಮಾಡಿ ಮತ್ತು ಕೇಬಲ್ ಬೆಚ್ಚಗಿರಬೇಕೆಂದು ಜಾಗ್ರತೆ ವಹಿಸಿ."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ಕಾಳಜಿ ಹಂತಗಳನ್ನು ನೋಡಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 271c976b3364..ef4a5f63d0d3 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"설정 순서 수정"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>페이지 중 <xliff:g id="ID_1">%1$d</xliff:g>페이지"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"잠금 화면"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"펼치기"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"최소화"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"닫기"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"설정"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"아래로 드래그하여 닫기"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"메뉴"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g>에서 PIP 사용 중"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g>에서 이 기능이 사용되는 것을 원하지 않는 경우 탭하여 설정을 열고 기능을 사용 중지하세요."</string>
- <string name="pip_play" msgid="333995977693142810">"재생"</string>
- <string name="pip_pause" msgid="1139598607050555845">"일시중지"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"다음으로 건너뛰기"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"이전으로 건너뛰기"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"크기 조절"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"발열로 인해 휴대전화 전원이 종료됨"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"휴대전화가 정상적으로 실행 중입니다."</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"이제 휴대전화가 정상적으로 작동합니다.\n자세히 알아보려면 탭하세요."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"휴대전화가 과열되어 온도를 낮추기 위해 전원이 종료되었습니다. 지금은 휴대전화가 정상적으로 실행 중입니다.\n\n휴대전화가 과열되는 이유는 다음과 같습니다.\n • 리소스를 많이 사용하는 앱 사용(예: 게임, 동영상 또는 내비게이션 앱)\n • 대용량 파일을 다운로드 또는 업로드\n • 온도가 높은 곳에서 휴대폰 사용"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"해결 방법 확인하기"</string>
<string name="high_temp_title" msgid="2218333576838496100">"휴대전화 온도가 높음"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다."</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"휴대전화 온도를 낮추는 동안 일부 기능이 제한됩니다.\n자세히 알아보려면 탭하세요."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"휴대전화 온도를 자동으로 낮추려고 시도합니다. 휴대전화를 계속 사용할 수는 있지만 작동이 느려질 수도 있습니다.\n\n휴대전화 온도가 낮아지면 정상적으로 작동됩니다."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"해결 방법 확인하기"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"충전기를 연결 해제하세요"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"기기를 충전하는 중에 문제가 발생했습니다. 케이블이 뜨거울 수 있으므로 주의하여 전원 어댑터를 분리하세요."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"취해야 할 조치 확인"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 9aa5e36152eb..cfd91b56ddf5 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Жөндөөлөрдүн иретин өзгөртүү."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ичинен <xliff:g id="ID_1">%1$d</xliff:g>-бет"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Кулпуланган экран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Жайып көрсөтүү"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Кичирейтүү"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Жабуу"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Жөндөөлөр"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Четке кагуу үчүн төмөн сүйрөңүз"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Меню"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> – сүрөт ичиндеги сүрөт"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Эгер <xliff:g id="NAME">%s</xliff:g> колдонмосу бул функцияны пайдаланбасын десеңиз, жөндөөлөрдү ачып туруп, аны өчүрүп коюңуз."</string>
- <string name="pip_play" msgid="333995977693142810">"Ойнотуу"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Тындыруу"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Кийинкисине өткөрүп жиберүү"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Мурункусуна өткөрүп жиберүү"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Өлчөмүн өзгөртүү"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон ысыгандыктан өчүрүлдү"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Телефонуңуз кадимкидей иштеп жатат"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефонуңуз кадимкидей иштеп жатат.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонуңуз өтө ысып кеткендиктен, аны муздатуу үчүн өчүрүлдү. Эми телефонуңуз кадимкидей иштеп жатат.\n\nТелефонуңуз төмөнкү шарттарда ысып кетиши мүмкүн:\n • Ашыкча ресурс короткон колдонмолорду (оюндар, видео же чабыттоо колдонмолору) пайдалансаңыз \n • Ири көлөмдөгү файлдарды жүктөп алсаңыз же берсеңиз\n • Телефонуңузду жогорку температураларда пайдалансаңыз"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Тейлөө кадамдарын көрүңүз"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефонуңуз ысып баратат"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Телефон сууганча айрым элементтердин иши чектелген"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Телефон сууганча айрым элементтердин иши чектелген.\nКеңири маалымат алуу үчүн таптап коюңуз"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонуңуз автоматтык түрдө сууйт. Аны колдоно берсеңиз болот, бирок ал жайыраак иштеп калат.\n\nТелефонуңуз суугандан кийин адаттагыдай эле иштеп баштайт."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Тейлөө кадамдарын көрүңүз"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Кубаттагычты сууруңуз"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Бул түзмөктү кубаттоодо маселе келип чыкты. Кабель ысып кетиши мүмкүн, андыктан кубаттагыч адаптерин сууруп коюңуз."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Тейлөө кадамдарын көрүңүз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index fcffa124ec91..90b5ad2267ac 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ແກ້ໄຂລຳດັບການຕັ້ງຄ່າ."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> ຈາກທັງໝົດ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ໜ້າຈໍລັອກ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ຂະຫຍາຍ"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ຫຍໍ້"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ປິດ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ການຕັ້ງຄ່າ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ລາກລົງເພື່ອປິດໄວ້"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ເມນູ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ແມ່ນເປັນການສະແດງຜົນຫຼາຍຢ່າງພ້ອມກັນ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"ຫາກທ່ານບໍ່ຕ້ອງການ <xliff:g id="NAME">%s</xliff:g> ໃຫ້ໃຊ້ຄຸນສົມບັດນີ້, ໃຫ້ແຕະເພື່ອເປີດການຕັ້ງຄ່າ ແລ້ວປິດມັນໄວ້."</string>
- <string name="pip_play" msgid="333995977693142810">"ຫຼິ້ນ"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ຢຸດຊົ່ວຄາວ"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ຂ້າມໄປລາຍການໜ້າ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ຂ້າມໄປລາຍການກ່ອນນີ້"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ປ່ຽນຂະໜາດ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ປິດໂທລະສັບເນື່ອງຈາກຮ້ອນເກີນໄປ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ໂທລະສັບຂອງທ່ານຕອນນີ້ເຮັດວຽກປົກກະຕິແລ້ວ"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"ໂທລະສັບຂອງທ່ານຕອນນີ້ເຮັດວຽກປົກກະຕິແລ້ວ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ໂທລະສັບຂອງທ່ານຮ້ອນເກີນໄປ, ດັ່ງນັ້ນມັນຈຶ່ງຖືກປິດໄວ້ເພື່ອໃຫ້ເຢັນກ່ອນ. ໂທລະສັບຂອງທ່ານຕອນນີ້ເຮັດວຽກປົກກະຕິແລ້ວ.\n\nໂທລະສັບຂອງທ່ານອາດຮ້ອນຫາກວ່າທ່ານ:\n • ໃຊ້ແອັບທີ່ກິນຊັບພະຍາກອນຫຼາຍ (ເຊັ່ນ: ເກມ, ວິດີໂອ ຫຼື ແອັບການນຳທາງ)\n • ດາວໂຫລດ ຫຼື ອັບໂຫລດຮູບພາບຂະໜາດໃຫຍ່\n • ໃຊ້ໂທລະສັບຂອງທ່ານໃນບ່ອນທີ່ມີອຸນຫະພູມສູງ"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ໂທລະສັບກຳລັງຮ້ອນຂຶ້ນ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ເນື່ອງໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ຄຸນສົມບັດບາງຢ່າງຖືກຈຳກັດໄວ້ໃນເວລາຫຼຸດອຸນຫະພູມຂອງໂທລະສັບ.\nແຕະເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ໂທລະສັບຂອງທ່ານຈະພະຍາຍາມລົດອຸນຫະພູມລົງ. ທ່ານຍັງຄົງສາມາດໃຊ້ໂທລະສັບຂອງທ່ານໄດ້ຢູ່, ແຕ່ມັນຈະເຮັດວຽກຊ້າລົງ.\n\nເມື່ອໂທລະສັບຂອງທ່ານບໍ່ຮ້ອນຫຼາຍແລ້ວ, ມັນຈະກັບມາເຮັດວຽກຕາມປົກກະຕິ."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ຖອດສາຍສາກອອກ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ເກີດບັນຫາໃນການສາກໄຟອຸປະກອນນີ້. ກະລຸນາຖອດສາຍສາກອອກ ແລະ ລະວັງເນື່ອງຈາກສາຍອາດຈະຍັງອຸ່ນຢູ່."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ເບິ່ງຂັ້ນຕອນການເບິ່ງແຍງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 3d19a913a5b4..5c8e8d9ac8fb 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Redaguoti nustatymų tvarką."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g> psl. iš <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Užrakinimo ekranas"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Išskleisti"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Sumažinti"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Uždaryti"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Nustatymai"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Nuvilkite žemyn, kad atsisakytumėte"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meniu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> rodom. vaizdo vaizde"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Jei nenorite, kad „<xliff:g id="NAME">%s</xliff:g>“ naudotų šią funkciją, palietę atidarykite nustatymus ir išjunkite ją."</string>
- <string name="pip_play" msgid="333995977693142810">"Leisti"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pristabdyti"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Praleisti ir eiti į kitą"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Praleisti ir eiti į ankstesnį"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Pakeisti dydį"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonas išjungt., nes įkaito"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Dabar telefonas veikia įprastai"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonas dabar veikia normaliai.\nPalietę gausite daugiau informacijos"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonas per daug įkaito, todėl buvo išj., kad atvėstų. Dabar telefonas veikia įprastai.\n\nTelefonas gali per daug įkaisti, jei:\n • esate įjungę daug išteklių naudoj. progr. (pvz., žaidimų, vaizdo įr. arba navig. progr.);\n • atsis. arba įkeliate didelius failus;\n • telefoną naudojate aukštoje temper."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Žr. priežiūros veiksmus"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefonas kaista"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Kai kurios funkcijos gali neveikti, kol telefonas vėsta.\nPalietę gausite daugiau informacijos"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonas automatiškai bandys atvėsti. Telefoną vis tiek galėsite naudoti, tačiau jis gali veikti lėčiau.\n\nKai telefonas atvės, jis veiks įprastai."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Žr. priežiūros veiksmus"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Atjunkite kroviklį"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Įkraunant šį įrenginį iškilo problema. Atjunkite maitinimo adapterį. Būkite atsargūs, nes laidas gali būti įkaitęs."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Žr. priežiūros veiksmus"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 42dc57c189c1..01bbdca17a3d 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Rediģēt iestatījumu secību."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. lpp. no <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Bloķēšanas ekrāns"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Izvērst"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizēt"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Aizvērt"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Iestatījumi"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Velciet lejup, lai noraidītu"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Izvēlne"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ir attēlā attēlā"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ja nevēlaties lietotnē <xliff:g id="NAME">%s</xliff:g> izmantot šo funkciju, pieskarieties, lai atvērtu iestatījumus un izslēgtu funkciju."</string>
- <string name="pip_play" msgid="333995977693142810">"Atskaņot"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Apturēt"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Pāriet uz nākamo"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Pāriet uz iepriekšējo"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Mainīt lielumu"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Tālrunis izslēgts karstuma dēļ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Tagad jūsu tālrunis darbojas normāli"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Tagad jūsu tālrunis darbojas normāli.\nPieskarieties, lai uzzinātu vairāk."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Jūsu tālrunis bija pārkarsis un tika izslēgts. Tagad tas darbojas normāli.\n\nTālrunis var sakarst, ja:\n • tiek izmantotas lietotnes, kas patērē daudz enerģijas (piem., spēles, video lietotnes vai navigācija);\n • tiek lejupielādēti/augšupielādēti lieli faili;\n • tālrunis tiek lietots augstā temperatūrā."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Skatīt apkopes norādījumus"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Tālrunis kļūst silts"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Dažas funkcijas ir ierobežotas, kamēr tālrunis mēģina atdzist"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Dažas funkcijas ir ierobežotas, kamēr notiek tālruņa atdzišana.\nPieskarieties, lai uzzinātu vairāk."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Jūsu tālrunis automātiski mēģinās atdzist. Jūs joprojām varat izmantot tālruni, taču tas, iespējams, darbosies lēnāk.\n\nTiklīdz tālrunis būs atdzisis, tas darbosies normāli."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Skatīt apkopes norādījumus"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Lādētāja atvienošana"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Uzlādējot šo ierīci, radās problēma. Atvienojiet strāvas adapteri. Esiet uzmanīgs — vads var būt uzsilis."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Skatīt apkopes norādījumus"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 39af976fc437..5a000de3e843 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Уредете го редоследот на поставките."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заклучен екран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Проширете"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Минимизирај"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Затвори"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Поставки"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Повлечете надолу за да отфрлите"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Мени"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> е во слика во слика"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ако не сакате <xliff:g id="NAME">%s</xliff:g> да ја користи функцијава, допрете за да ги отворите поставките и да ја исклучите."</string>
- <string name="pip_play" msgid="333995977693142810">"Пушти"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Паузирај"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Прескокни до следната"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Прескокни до претходната"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Промени големина"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефонот се исклучи поради загреаност"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Сега телефонот работи нормално"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Сега телефонот работи нормално.\nДопрете за повеќе информации"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефонот беше премногу загреан, така што се исклучи за да се олади. Сега работи нормално.\n\nТелефонот може премногу да се загрее ако:\n • користите апликации што работат со многу ресурси (како што се, на пример, апликациите за видеа, навигација или игри)\n • преземате или поставувате големи датотеки\n •го користите телефонот на високи температури"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Прикажи ги чекорите за грижа за уредот"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефонот се загрева"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Некои функции се ограничени додека телефонот се лади"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Некои функции се ограничени додека телефонот се лади.\nДопрете за повеќе информации"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефонот автоматски ќе се обиде да се олади. Вие сепак ќе може да го користите, но тој може да работи побавно.\n\nОткако ќе се олади, ќе работи нормално."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Прикажи ги чекорите за грижа за уредот"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Исклучете го полначот"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Има проблем со полнењето на уредов. Исклучете го адаптерот за напојување и внимавајте зошто кабелот може да е топол."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Прикажи ги чекорите за грижа за уредот"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 34f1ac6cfeaf..e3a3f82f9d6e 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ക്രമീകരണ ക്രമം എഡിറ്റുചെയ്യുക."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"പേജ് <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ലോക്ക് സ്‌ക്രീൻ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"വികസിപ്പിക്കുക"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ചെറുതാക്കുക‍"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"അവസാനിപ്പിക്കുക"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ക്രമീകരണം"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"തള്ളിക്കളയാൻ താഴേക്ക് വലിച്ചിടുക"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"മെനു"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ചിത്രത്തിനുള്ളിൽ ചിത്രം രീതിയിലാണ്"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ഈ ഫീച്ചർ ഉപയോഗിക്കേണ്ടെങ്കിൽ, ടാപ്പ് ചെയ്‌ത് ക്രമീകരണം തുറന്ന് അത് ഓഫാക്കുക."</string>
- <string name="pip_play" msgid="333995977693142810">"പ്ലേ ചെയ്യുക"</string>
- <string name="pip_pause" msgid="1139598607050555845">"താൽക്കാലികമായി നിർത്തുക"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"അടുത്തതിലേക്ക് പോകുക"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"മുമ്പത്തേതിലേക്ക് പോകുക"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"വലുപ്പം മാറ്റുക"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ചൂട് കൂടിയതിനാൽ ഫോൺ ഓഫാക്കി"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ഫോൺ ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നു"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ഫോൺ ചൂടായിരിക്കുന്നതിനാൽ തണുക്കാൻ ഓഫാക്കിയിരിക്കുന്നു. ഫോൺ ഇപ്പോൾ സാധാരണഗതിയിൽ പ്രവർത്തിക്കുന്നു.\n\nഫോണിന് ചൂട് കൂടാൻ കാരണം:\n • ഗെയിമിംഗ്, വീഡിയോ അല്ലെങ്കിൽ നാവിഗേഷൻ തുടങ്ങിയ റിസോഴ്സ്-ഇന്റൻസീവായ ആപ്പുകൾ ഉപയോഗിക്കുന്നത്\n • വലിയ ഫയലുകൾ അപ്‌ലോഡോ ഡൗൺലോഡോ ചെയ്യുന്നത്\n • ഉയർന്ന താപനിലയിൽ ഫോൺ ഉപയോഗിക്കുന്നത്"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ഫോൺ ചൂടായിക്കൊണ്ടിരിക്കുന്നു"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ഫോൺ തണുത്തുകൊണ്ടിരിക്കുമ്പോൾ ചില ഫീച്ചറുകൾ പരിമിതപ്പെടുത്തപ്പെടും"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"നിങ്ങളുടെ ഫോൺ സ്വയമേവ തണുക്കാൻ ശ്രമിക്കും. നിങ്ങൾക്ക് അപ്പോഴും ഫോൺ ഉപയോഗിക്കാമെങ്കിലും പ്രവർത്തനം മന്ദഗതിയിലായിരിക്കും.\n\nതണുത്തുകഴിഞ്ഞാൽ, ഫോൺ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കും."</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ചാർജർ അൺപ്ലഗ് ചെയ്യുക"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ഈ ഉപകരണം ചാർജ് ചെയ്യുന്നതിൽ തടസ്സമുണ്ട്. പവർ അഡാപ്റ്റർ അൺപ്ലഗ് ചെയ്യുക, കേബിളിന് ചൂടുണ്ടായിരിക്കുമെന്നതിനാൽ ശ്രദ്ധിക്കണം."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"മുൻകരുതൽ നടപടികൾ കാണുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 13ad38f48cad..8141ef3a1fc6 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Тохиргооны дарааллыг өөрчилнө үү."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>-н <xliff:g id="ID_1">%1$d</xliff:g>-р хуудас"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Түгжигдсэн дэлгэц"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Дэлгэх"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Багасгах"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Хаах"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Тохиргоо"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Хаахын тулд доош чирэх"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Цэс"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> дэлгэцэн доторх дэлгэцэд байна"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Та <xliff:g id="NAME">%s</xliff:g>-д энэ онцлогийг ашиглуулахыг хүсэхгүй байвал тохиргоог нээгээд, үүнийг унтраана уу."</string>
- <string name="pip_play" msgid="333995977693142810">"Тоглуулах"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Түр зогсоох"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Дараагийн медиад очих"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Өмнөх медиад очих"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Хэмжээг өөрчлөх"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Халснаас үүдэн утас унтарсан"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Таны утас одоо хэвийн ажиллаж байна"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Таны утас одоо хэвийн ажиллаж байна.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Таны утас хэт халсан тул хөргөхөөр унтраасан болно. Таны утас одоо хэвийн ажиллаж байна.\n\nХэрэв та дараахыг хийвэл таны утас хэт халж болзошгүй:\n • Их хэмжээний нөөц хэрэглээний апп (тоглоом, видео эсвэл шилжилтийн апп зэрэг)\n • Багтаамж ихтэй файл татах, байршуулах\n • Утсаа өндөр температурт ашиглах"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Хянамж болгоомжийн алхмыг харах"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Утас халж эхэлж байна"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Таны утас хөрж байх зуур зарим онцлогийг хязгаарласан"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Утсыг хөрөх үед зарим онцлогийг хязгаарлана.\nДэлгэрэнгүй мэдээлэл авах бол товшино уу"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Таны утас автоматаар хөрөх болно. Та утсаа ашиглаж болох хэдий ч удаан ажиллаж болзошгүй.\n\nТаны утас хөрсний дараагаар хэвийн ажиллана."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Хянамж болгоомжийн алхмыг харах"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Цэнэглэгчийг салгана уу"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Энэ төхөөрөмжийг цэнэглэхэд асуудал гарлаа. Тэжээлийн залгуурыг салгана уу. Кабель халсан байж болзошгүй тул болгоомжтой байгаарай."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Хянамж болгоомжийн алхмыг харна уу"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 90a937e319b8..4f1476e9a30c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिंग्जचा क्रम संपादित करा."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"पृष्ठ <xliff:g id="ID_2">%2$d</xliff:g> पैकी <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लॉक स्‍क्रीन"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"विस्तृत करा"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"लहान करा"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"बंद करा"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"सेटिंग्ज"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"डिसमिस करण्यासाठी खाली ड्रॅग करा"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"मेनू"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> चित्रामध्ये चित्र मध्ये आहे"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g>ने हे वैशिष्ट्य वापरू नये असे तुम्हाला वाटत असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
- <string name="pip_play" msgid="333995977693142810">"प्ले करा"</string>
- <string name="pip_pause" msgid="1139598607050555845">"थांबवा"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"डावलून पुढे जा"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"डावलून मागे जा"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"आकार बदला"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"तापल्‍यामुळे फोन बंद झाला"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"तुमचा फोन आता व्‍यवस्थित सुरू आहे"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तुमचा फोन खूप तापलाय, म्हणून तो थंड होण्यासाठी बंद झाला आहे. तुमचा फोन आता व्‍यवस्थित सुरू आहे.\n\nतुम्ही असे केल्यास तुमचा फोन खूप तापेल:\n •संसाधन केंद्रित अ‍ॅप वापरणे (गेमिंग, व्हिडिओ किंवा नेव्हिगेशन अ‍ॅप यासारखे)\n •मोठ्या फाइल डाउनलोड किंवा अपलोड करणे\n •उच्च तापमानामध्ये तुमचा फोन वापरणे"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"फोन ऊष्ण होत आहे"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"फोन थंड होत असताना काही वैशिष्‍ट्ये मर्यादित असतात"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"तुमचा फोन स्वयंचलितपणे थंड होईल. तुम्ही अद्यापही तुमचा फोन वापरू शकता परंतु तो कदाचित धीमेपणे कार्य करेल.\n\nतुमचा फोन एकदा थंड झाला की, तो सामान्यपणे कार्य करेल."</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग करा"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"हे डिव्हाइस चार्ज करताना समस्या आहे. पॉवर अडॅप्टर अनप्लग करा आणि शक्य तेवढी काळजी घ्या कदाचित केबल गरम असू शकते."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"काय काळजी घ्यावी ते पाहा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b2bfa707a58a..37cbb7edf753 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edit susunan tetapan."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Halaman <xliff:g id="ID_1">%1$d</xliff:g> daripada <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Kunci skrin"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Kembangkan"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimumkan"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Tutup"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Tetapan"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Seret ke bawah untuk mengetepikan"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> terdapat dalam gambar dalam gambar"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Jika anda tidak mahu <xliff:g id="NAME">%s</xliff:g> menggunakan ciri ini, ketik untuk membuka tetapan dan matikan ciri."</string>
- <string name="pip_play" msgid="333995977693142810">"Main"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Jeda"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Langkau ke seterusnya"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Langkau ke sebelumnya"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ubah saiz"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon dimatikan kerana panas"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon anda kini berjalan seperti biasa"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon anda kini berjalan seperti biasa.\nKetik untuk mendapatkan maklumat lanjut"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon anda terlalu panas, jadi telefon itu telah dimatikan untuk menyejuk. Sekarang, telefon anda berjalan seperti biasa.\n\nTelefon anda mungkin menjadi terlalu panas jika anda:\n • Menggunakan apl intensif sumber (seperti permainan, video atau apl navigasi)\n • Memuat turun atau memuat naik fail besar\n • Menggunakan telefon anda dalam suhu tinggi"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Lihat langkah penjagaan"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon semakin panas"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Sesetengah ciri adalah terhad semasa telefon menyejuk"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Sesetengah ciri adalah terhad semasa telefon menyejuk.\nKetik untuk mendapatkan maklumat lanjut"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon anda akan cuba menyejuk secara automatik. Anda masih dapat menggunakan telefon itu tetapi telefon tersebut mungkin berjalan lebih perlahan.\n\nSetelah telefon anda sejuk, telefon itu akan berjalan seperti biasa."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Lihat langkah penjagaan"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Cabut palam pengejas"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Terdapat isu semasa mengecas peranti ini. Cabut palam penyesuai kuasa. Berhati-hati kerana kabel mungkin hangat."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Lihat langkah penjagaan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 96f1d1bbfdab..376ed2fd2d9a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ဆက်တင်များ၏ အစီအစဉ်ကို တည်းဖြတ်ပါ။"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"စာမျက်နှာ <xliff:g id="ID_2">%2$d</xliff:g> အနက်မှ စာမျက်နှာ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"လော့ခ်ချထားချိန် မျက်နှာပြင်"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ချဲ့ရန်"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ချုံ့ရန်"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ပိတ်ရန်"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ဆက်တင်များ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ပယ်ရန်အတွက် အောက်သို့ ပွတ်ဆွဲပါ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"မီနူး"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> သည် တစ်ခုပေါ် တစ်ခုထပ်၍ ဖွင့်ထားသည်"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> အား ဤဝန်ဆောင်မှုကို အသုံးမပြုစေလိုလျှင် ဆက်တင်ကိုဖွင့်ရန် တို့ပြီး ၎င်းဝန်ဆောင်မှုကို ပိတ်လိုက်ပါ။"</string>
- <string name="pip_play" msgid="333995977693142810">"ဖွင့်ရန်"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ခေတ္တရပ်ရန်"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"နောက်တစ်ခုသို့ ကျော်ရန်"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ယခင်တစ်ခုသို့ ပြန်သွားရန်"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"အရွယ်အစားပြောင်းရန်"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"အပူရှိန်ကြောင့်ဖုန်းပိတ်ထားသည်"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"သင်၏ဖုန်းသည် ပုံမှန် အလုပ်လုပ်နေပါသည်"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"သင့်ဖုန်းသည် ယခု ပုံမှန်အလုပ်လုပ်နေပါပြီ။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"သင့်ဖုန်းအလွန်ပူနေသည့်အတွက် အေးသွားစေရန် ပိတ်ထားပါသည်။ ယခုပုံမှန် အလုပ်လုပ်ပါပြီ။\n\nအောက်ပါတို့ကိုသုံးလျှင် ပူလာပါမည်-\n • အရင်းအမြစ်များသောအက်ပ်ကို သုံးခြင်း (ဥပမာ ဂိမ်းကစားခြင်း၊ ဗီဒီယိုကြည့်ခြင်း (သို့) လမ်းညွှန်အက်ပ်)\n • ကြီးမားသောဖိုင်များ ဒေါင်းလုဒ် (သို့) အပ်လုဒ်လုပ်ခြင်း\n • အပူရှိန်မြင့်သောနေရာတွင် သုံးခြင်း"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
<string name="high_temp_title" msgid="2218333576838496100">"ဖုန်း ပူနွေးလာပါပြီ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ဖုန်းကို အေးအောင်ပြုလုပ်နေစဉ်တွင် အချို့ဝန်ဆောင်မှုများကို ကန့်သတ်ထားပါသည်။\nနောက်ထပ်အချက်အလက်များအတွက် တို့ပါ"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"သင့်ဖုန်းသည် အလိုအလျောက် ပြန်အေးသွားပါလိမ့်မည်။ ဖုန်းကို အသုံးပြုနိုင်ပါသေးသည် သို့သော် ပိုနှေးနိုင်ပါသည်။\n\nသင့်ဖုန်း အေးသွားသည်နှင့် ပုံမှန်အတိုင်း ပြန်အလုပ်လုပ်ပါလိမ့်မည်။"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"အားသွင်းကိရိယာ ပလပ်ဖြုတ်ပါ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ဤစက်ပစ္စည်းကို အားသွင်းရာတွင် ပြဿနာရှိနေသည်။ ပါဝါ ကြားခံကိရိယာကို ပလပ်ဖြုတ်ပါ။ ကေဘယ်ကြိုး ပူနွေးနေနိုင်သဖြင့် သတိထားပါ။"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ဂရုပြုစရာ အဆင့်များ ကြည့်ရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b717273f084c..26268301333c 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Endre rekkefølgen på innstillingene."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Side <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låseskjerm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Vis"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimer"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Lukk"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Innstillinger"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Dra ned for å avvise"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meny"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> er i bilde-i-bilde"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Hvis du ikke vil at <xliff:g id="NAME">%s</xliff:g> skal bruke denne funksjonen, kan du trykke for å åpne innstillingene og slå den av."</string>
- <string name="pip_play" msgid="333995977693142810">"Spill av"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Sett på pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Hopp til neste"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Hopp til forrige"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Endre størrelse"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon ble slått av pga varme"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefonen din kjører nå som normalt"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonen kjører nå som normalt.\nTrykk for å se mer informasjon"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonen din var for varm, så den ble slått av for å kjøles ned. Telefonen din kjører nå som normalt.\n\nTelefonen kan blir for varm hvis du:\n • bruker ressurskrevende apper (for eksempel spill-, video- eller navigeringsapper)\n • laster store filer opp eller ned\n • bruker telefonen ved høy temperatur"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Se vedlikeholdstrinnene"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefonen begynner å bli varm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Enkelte funksjoner er begrenset mens telefonen kjøles ned"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Enkelte funksjoner er begrenset mens telefonen kjøles ned.\nTrykk for å se mer informasjon"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonen din kommer til å prøve å kjøle seg ned automatisk. Du kan fremdeles bruke telefonen, men den kjører muligens saktere.\n\nTelefonen kommer til å kjøre som normalt, når den har kjølt seg ned."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Se vedlikeholdstrinnene"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Koble fra laderen"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det oppsto et problem med lading av enheten. Koble fra strømadapteren, og vær forsiktig, kabelen kan være varm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Se vedlikeholdstrinnene"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 4d0d2ef2cefa..3cf586c0f4f6 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"सेटिङहरूको क्रमलाई सम्पादन गर्नुहोस्।"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> मध्ये पृष्ठ <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"लक स्क्रिन"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"विस्तृत गर्नुहोस्"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"सानो बनाउनुहोस्"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"बन्द गर्नुहोस्"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"सेटिङहरू"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"खारेज गर्न तल तान्नुहोस्"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"मेनु"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> Picture-in-picture मा छ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले सुविधा प्रयोग नगरोस् भन्ने चाहनुहुन्छ भने ट्याप गरेर सेटिङहरू खोल्नुहोस् र यसलाई निष्क्रिय पार्नुहोस्।"</string>
- <string name="pip_play" msgid="333995977693142810">"प्ले गर्नुहोस्"</string>
- <string name="pip_pause" msgid="1139598607050555845">"पज गर्नुहोस्"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"अर्कोमा जानुहोस्"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"अघिल्लोमा जानुहोस्"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"आकार बदल्नुहोस्"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"फोन अति नै तातिएकाले चिसिन बन्द भयो"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"तपाईंको फोन अब सामान्य ढंगले चल्दै छ"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"तपाईंको फोन अति नै तातिएकाले चिसिन बन्द भयो। तपाईंको फोन अब सामान्य ढंगले चल्दै छ।\n\nतपाईंले निम्न कुराहरू गर्नुभयो भने तपाईंको फोन अत्यन्त तातो हुनसक्छ:\n • धेरै संसाधन खपत गर्ने एपहरूको प्रयोग (जस्तै गेमिङ, भिडियो वा नेभिगेसन एपहरू)\n • ठूला फाइलहरूको डाउनलोड वा अपलोड\n • उच्च तापक्रममा फोनको प्रयोग"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"फोन तातो भइरहेको छ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"फोन चिसो हुँदै गर्दा केही विशेषताहरूलाई सीमित गरिन्छ"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"तपाईंको फोन स्वतः चिसो हुने प्रयास गर्ने छ। तपाईं अझै पनि आफ्नो फोनको प्रयोग गर्न सक्नुहुन्छ तर त्यो अझ ढिलो चल्न सक्छ।\n\nचिसो भएपछि तपाईंको फोन सामान्य गतिमा चल्नेछ।"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"चार्जर अनप्लग गर्नुहोस्‌"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"यो यन्त्र चार्ज गर्दा कुनै समस्या भयो। पावर एडाप्टर अनप्लग गर्नुहोस्‌ र केबल तातो हुन सक्ने भएकाले ध्यान दिनुहोस्‌।"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"हेरचाहसम्बन्धी चरणहरू हेर्नुहोस्‌"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 36d1d61b3e40..7a4de7516e05 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Volgorde van instellingen bewerken."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Vergrendelscherm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Uitvouwen"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimaliseren"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Sluiten"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Instellingen"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Sleep omlaag om te sluiten"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> is in scherm-in-scherm"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Als je niet wilt dat <xliff:g id="NAME">%s</xliff:g> deze functie gebruikt, tik je om de instellingen te openen en schakel je de functie uit."</string>
- <string name="pip_play" msgid="333995977693142810">"Afspelen"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Onderbreken"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Doorgaan naar volgende"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Teruggaan naar vorige"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Formaat aanpassen"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefoon uitgezet wegens hitte"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Je telefoon presteert nu weer zoals gebruikelijk"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Je telefoon functioneert nu weer zoals gebruikelijk.\nTik voor meer informatie"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Je telefoon was te warm en is uitgeschakeld om af te koelen. Je telefoon presteert nu weer zoals gebruikelijk.\n\nJe telefoon kan warm worden als je:\n • bronintensieve apps gebruikt (zoals game-, video-, of navigatie-apps),\n • grote bestanden up- of downloadt,\n • je telefoon gebruikt bij hoge temperaturen."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Onderhoudsstappen bekijken"</string>
<string name="high_temp_title" msgid="2218333576838496100">"De telefoon wordt warm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Bepaalde functies zijn beperkt terwijl de telefoon afkoelt.\nTik voor meer informatie"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Je telefoon probeert automatisch af te koelen. Je kunt je telefoon nog steeds gebruiken, maar deze kan langzamer werken.\n\nZodra de telefoon is afgekoeld, werkt deze weer normaal."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Onderhoudsstappen bekijken"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Oplader loskoppelen"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Er is een probleem met het opladen van dit apparaat. Koppel de voedingsadapter los. Wees voorzichtig, want de kabel kan warm zijn."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Onderhoudsstappen bekijken"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 6168e0c417ae..c74a69a1e579 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ସେଟିଙ୍ଗର କ୍ରମ ସଂଶୋଧନ କରନ୍ତୁ।"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"ପୃଷ୍ଠା <xliff:g id="ID_1">%1$d</xliff:g> ମୋଟ <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"ଲକ୍‌ ସ୍କ୍ରୀନ୍‌"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ବଢ଼ାନ୍ତୁ"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ଛୋଟ କରନ୍ତୁ"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ବନ୍ଦ କରନ୍ତୁ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ସେଟିଂସ୍"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ଖାରଜ କରିବାକୁ ତଳକୁ ଟାଣନ୍ତୁ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ମେନୁ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> \"ଛବି-ଭିତରେ-ଛବି\"ରେ ଅଛି"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"ଏହି ବୈଶିଷ୍ଟ୍ୟ <xliff:g id="NAME">%s</xliff:g> ବ୍ୟବହାର ନକରିବାକୁ ଯଦି ଆପଣ ଚାହାଁନ୍ତି, ସେଟିଙ୍ଗ ଖୋଲିବାକୁ ଟାପ୍‍ କରନ୍ତୁ ଏବଂ ଏହା ଅଫ୍‍ କରିଦିଅନ୍ତୁ।"</string>
- <string name="pip_play" msgid="333995977693142810">"ପ୍ଲେ କରନ୍ତୁ"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ପଜ୍‍ କରନ୍ତୁ"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ପରବର୍ତ୍ତୀକୁ ଯାଆନ୍ତୁ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ପୂର୍ବବର୍ତ୍ତୀକୁ ଛାଡ଼ନ୍ତୁ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ରିସାଇଜ୍ କରନ୍ତୁ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ଗରମ ହେତୁ ଫୋନ୍‍ ଅଫ୍‍ କରିଦିଆଗଲା"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ଆପଣଙ୍କ ଫୋନ୍‍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ଅବସ୍ଥାରେ ଚାଲୁଛି"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ଆପଣଙ୍କ ଫୋନ୍‍ ବହୁତ ଗରମ ଥିଲା, ତେଣୁ ଏହାକୁ ଥଣ୍ଡା କରାଯିବାକୁ ଅଫ୍‍ କରିଦିଆଗଲା। ଆପଣଙ୍କ ଫୋନ୍‍ ବର୍ତ୍ତମାନ ସାମାନ୍ୟ ଅବସ୍ଥାରେ ଚାଲୁଛି।\n\nଆପଣଙ୍କ ଫୋନ୍‍ ଅଧିକ ଗରମ ହୋଇଯାଇପାରେ ଯଦି ଆପଣ:\n • ରିସୋର୍ସ-ଇଣ୍ଟେନସିଭ୍‍ ଆପ୍‍ (ଯେପରିକି ଗେମିଙ୍ଗ, ଭିଡିଓ, କିମ୍ବା ନେଭିଗେସନ୍‍ ଆପ୍‍) ବ୍ୟବହାର କରନ୍ତି\n • ବଡ ଫାଇଲ୍‍ ଡାଉନଲୋଡ୍ କିମ୍ବା ଅପଲୋଡ୍‍ କରନ୍ତି\n • ଅଧିକ ତାପମାତ୍ରାରେ ଆପଣଙ୍କ ଫୋନ୍‍ ବ୍ୟବହାର କରନ୍ତି"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ଫୋନ୍‍ ଗରମ ହୋଇଯାଉଛି"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ଫୋନ୍‍ ଥଣ୍ଡା ହେବା ସମୟରେ କିଛି ଫିଚର୍ ସୀମିତ ଭାବେ କାମ କରିଥାଏ"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ଆପଣଙ୍କ ଫୋନ୍‍ ସ୍ୱଚାଳିତ ଭାବେ ଥଣ୍ଡା ହେବାକୁ ଚେଷ୍ଟା କରିବ। ଆପଣ ତଥାପି ନିଜ ଫୋନ୍‍ ବ୍ୟବହାର କରିପାରିବେ, କିନ୍ତୁ ଏହା ଧୀରେ ଚାଲିପାରେ।\n\nଆପଣଙ୍କ ଫୋନ୍‍ ଥଣ୍ଡା ହୋଇଯିବାପରେ, ଏହା ସାମାନ୍ୟ ଭାବେ ଚାଲିବ।"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ଚାର୍ଜର୍‍ ଅନ୍‍ପ୍ଲଗ୍‌ କରନ୍ତୁ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ଏହି ଡିଭାଇସ୍ ଚାର୍ଜ କରିବାରେ ଗୋଟିଏ ସମସ୍ୟା ଅଛି। ଯେହେତୁ କେବଳ ଗରମ ହୋଇଯାଇପାରେ, ତେଣୁ ପାୱାର୍ ଆଡପ୍ଟର୍ ଅନ୍‌ପ୍ଲଗ୍‌ କରନ୍ତୁ ଏବଂ ଯତ୍ନ ନିଅନ୍ତୁ।"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ସେବା ସମ୍ବନ୍ଧିତ ଷ୍ଟେପ୍‌ଗୁଡ଼ିକ ଦେଖନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 519606def5fe..7c462db7bb6a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ਸੈਟਿੰਗਾਂ ਦੇ ਕ੍ਰਮ ਦਾ ਸੰਪਾਦਨ ਕਰੋ।"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> ਦਾ <xliff:g id="ID_1">%1$d</xliff:g> ਪੰਨਾ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">" ਲਾਕ ਸਕ੍ਰੀਨ"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ਵਿਸਤਾਰ ਕਰੋ"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ਛੋਟਾ ਕਰੋ"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ਬੰਦ ਕਰੋ"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ਸੈਟਿੰਗਾਂ"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ਖਾਰਜ ਕਰਨ ਲਈ ਹੇਠਾਂ ਘਸੀਟੋ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"ਮੀਨੂ"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ਤਸਵੀਰ-ਅੰਦਰ-ਤਸਵੀਰ ਵਿੱਚ ਹੈ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"ਜੇਕਰ ਤੁਸੀਂ ਨਹੀਂ ਚਾਹੁੰਦੇ ਕਿ <xliff:g id="NAME">%s</xliff:g> ਐਪ ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਦੀ ਵਰਤੋਂ ਕਰੇ, ਤਾਂ ਸੈਟਿੰਗਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ ਅਤੇ ਇਸਨੂੰ ਬੰਦ ਕਰੋ।"</string>
- <string name="pip_play" msgid="333995977693142810">"ਚਲਾਓ"</string>
- <string name="pip_pause" msgid="1139598607050555845">"ਵਿਰਾਮ ਦਿਓ"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ਅਗਲੇ \'ਤੇ ਜਾਓ"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ਪਿਛਲੇ \'ਤੇ ਜਾਓ"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ਆਕਾਰ ਬਦਲੋ"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"ਗਰਮ ਹੋਣ ਕਾਰਨ ਫ਼ੋਨ ਬੰਦ ਹੋ ਗਿਆ"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">\n"ਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਸੀ, ਇਸ ਲਈ ਇਹ ਠੰਡਾ ਹੋਣ ਵਾਸਤੇ ਬੰਦ ਹੋ ਗਿਆ ਸੀ। ਤੁਹਾਡਾ ਫ਼ੋਨ ਹੁਣ ਸਹੀ ਚੱਲ ਰਿਹਾ ਹੈ।\n\nਤੁਹਾਡਾ ਫ਼ੋਨ ਬਹੁਤ ਗਰਮ ਹੋ ਸਕਦਾ ਹੈ ਜੇ:\n • ਤੁਸੀਂ ਸਰੋਤਾਂ ਦੀ ਵੱਧ ਵਰਤੋਂ ਵਾਲੀਆਂ ਐਪਾਂ (ਜਿਵੇਂ ਗੇਮਿੰਗ, ਵੀਡੀਓ, ਜਾਂ ਦਿਸ਼ਾ-ਨਿਰਦੇਸ਼ ਐਪਾਂ) ਵਰਤਦੇ ਹੋ • ਵੱਡੀਆਂ ਫ਼ਾਈਲਾਂ ਡਾਊਨਲੋਡ ਜਾਂ ਅੱਪਲੋਡ ਕਰਦੇ ਹੋ\n • ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਉੱਚ ਤਾਪਮਾਨਾਂ ਵਿੱਚ ਵਰਤਦੇ ਹੋ"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ਫ਼ੋਨ ਗਰਮ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ਫ਼ੋਨ ਦੇ ਠੰਡਾ ਹੋਣ ਦੇ ਦੌਰਾਨ ਕੁਝ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਸੀਮਿਤ ਹੁੰਦੀਆਂ ਹਨ"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਵੈਚਲਿਤ ਰੂਪ ਵਿੱਚ ਠੰਡਾ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੇਗਾ। ਤੁਸੀਂ ਹਾਲੇ ਵੀ ਆਪਣੇ ਫ਼ੋਨ ਨੂੰ ਵਰਤ ਸਕਦੇ ਹੋ, ਪਰੰਤੂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਇਹ ਵਧੇਰੇ ਹੌਲੀ ਚੱਲੇ।\n\nਇੱਕ ਵਾਰ ਠੰਡਾ ਹੋਣ ਤੋਂ ਬਾਅਦ ਤੁਹਾਡਾ ਫ਼ੋਨ ਸਧਾਰਨ ਤੌਰ \'ਤੇ ਚੱਲੇਗਾ।"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ਚਾਰਜਰ ਨੂੰ ਕੱਢੋ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਚਾਰਜ ਕਰਨ ਵਿੱਚ ਕੋਈ ਸਮੱਸਿਆ ਆ ਗਈ ਹੈ। ਪਾਵਰ ਅਡਾਪਟਰ ਨੂੰ ਕੱਢੋ ਅਤੇ ਧਿਆਨ ਰੱਖੋ ਸ਼ਾਇਦ ਕੇਬਲ ਗਰਮ ਹੋਵੇ।"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ਦੇਖਭਾਲ ਦੇ ਪੜਾਅ ਦੇਖੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index df819ef17b44..a1f8ea652235 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Edytuj kolejność ustawień."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strona <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran blokady"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Rozwiń"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimalizuj"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zamknij"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ustawienia"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Przeciągnij w dół, by zamknąć"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"Aplikacja <xliff:g id="NAME">%s</xliff:g> działa w trybie obraz w obrazie"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Jeśli nie chcesz, by aplikacja <xliff:g id="NAME">%s</xliff:g> korzystała z tej funkcji, otwórz ustawienia i wyłącz ją."</string>
- <string name="pip_play" msgid="333995977693142810">"Odtwórz"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Wstrzymaj"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Dalej"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Wstecz"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Zmień rozmiar"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon wyłączony: przegrzanie"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefon działa teraz normalnie"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon działa teraz normalnie\nKliknij, by dowiedzieć się więcej"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon był zbyt gorący i wyłączył się, by obniżyć temperaturę. Urządzenie działa teraz normalnie.\n\nTelefon może się przegrzać, gdy:\n • Używasz aplikacji zużywających dużo zasobów (np. gier, nawigacji czy odtwarzaczy filmów)\n • Pobierasz lub przesyłasz duże pliki\n • Używasz telefonu w wysokiej temperaturze"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobacz instrukcję postępowania"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon się nagrzewa"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Podczas obniżania temperatury telefonu niektóre funkcje są ograniczone\nKliknij, by dowiedzieć się więcej"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon automatycznie podejmie próbę obniżenia temperatury. Możesz go wciąż używać, ale telefon może działać wolniej.\n\nGdy temperatura się obniży, telefon będzie działał normalnie."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobacz instrukcję postępowania"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Odłącz ładowarkę"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Podczas ładowania tego urządzenia wystąpił błąd. Odłącz zasilacz, zwracając uwagę na kabel, który może być gorący."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobacz instrukcję postępowania"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 8751637ab4fe..c8eaa0ddc4fb 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expandir"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Fechar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Configurações"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arraste para baixo para dispensar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproduzir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Pular para a próxima"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Pular para a anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionar"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"O smartphone foi desligado devido ao aquecimento"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"O smartphone está sendo executado normalmente agora"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está sendo executado normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
<string name="high_temp_title" msgid="2218333576838496100">"O smartphone está esquentando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 11c94642cbc6..6b8b674ea412 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar a ordem das definições."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ecrã de bloqueio"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expandir"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Fechar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Definições"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arrastar para baixo para ignorar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"A app <xliff:g id="NAME">%s</xliff:g> está no modo de ecrã no ecrã"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se não pretende que a app <xliff:g id="NAME">%s</xliff:g> utilize esta funcionalidade, toque para abrir as definições e desative-a."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproduzir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Mudar para o seguinte"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Mudar para o anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionar"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telem. deslig. devido ao calor"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"O telemóvel está a funcionar normalmente"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"O seu telemóvel já está a funcionar normalmente.\nToque para obter mais informações."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O telemóvel estava muito quente, por isso desligou-se para arrefecer. Agora funciona normalmente.\n\nO telemóvel pode sobreaquecer se:\n • Utilizar aplicações que utilizam mais recursos (jogos, vídeo ou aplicações de navegação)\n • Transferir ou carregar ficheiros grandes\n • Utilizar em altas temperaturas"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Veja os passos de manutenção"</string>
<string name="high_temp_title" msgid="2218333576838496100">"O telemóvel está a aquecer"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Algumas funcionalidades são limitadas enquanto o telemóvel arrefece.\nToque para obter mais informações."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"O telemóvel tenta arrefecer automaticamente. Pode continuar a utilizá-lo, mas este poderá funcionar mais lentamente.\n\nAssim que o telemóvel tiver arrefecido, funcionará normalmente."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Veja os passos de manutenção"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desligar o carregador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema ao carregar este dispositivo. Desligue o transformador e tenha cuidado porque o cabo pode estar quente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver os passos a ter em consideração"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 8751637ab4fe..c8eaa0ddc4fb 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editar ordem das configurações."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Página <xliff:g id="ID_1">%1$d</xliff:g> de <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Tela de bloqueio"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Expandir"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizar"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Fechar"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Configurações"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Arraste para baixo para dispensar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> está em picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Se você não quer que o app <xliff:g id="NAME">%s</xliff:g> use este recurso, toque para abrir as configurações e desativá-lo."</string>
- <string name="pip_play" msgid="333995977693142810">"Reproduzir"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausar"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Pular para a próxima"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Pular para a anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionar"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"O smartphone foi desligado devido ao aquecimento"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"O smartphone está sendo executado normalmente agora"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"O smartphone está funcionando normalmente agora.\nToque para saber mais"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"O smartphone estava muito quente e foi desligado para resfriar. Agora, ele está sendo executado normalmente.\n\nO smartphone pode ficar quente demais se você:\n • usar apps que consomem muitos recursos (como apps de jogos, vídeos ou navegação);\n • fizer o download ou upload de arquivos grandes;\n • usar o smartphone em temperaturas altas."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Ver etapas de cuidado"</string>
<string name="high_temp_title" msgid="2218333576838496100">"O smartphone está esquentando"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Alguns recursos ficam limitados enquanto o smartphone é resfriado"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Alguns recursos ficam limitados enquanto o smartphone é resfriado.\nToque para saber mais"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Seu smartphone tentará se resfriar automaticamente. Você ainda poderá usá-lo, mas talvez ele fique mais lento.\n\nQuando o smartphone estiver resfriado, ele voltará ao normal."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Ver etapas de cuidado"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Desconecte o carregador"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ocorreu um problema com o carregamento deste dispositivo. Desconecte o adaptador de energia com cuidado, já que o cabo pode estar quente."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Ver etapas de cuidado"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7529f046a734..08542c02c2e0 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Editați ordinea setărilor."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> din <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ecran de blocare"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Extindeți"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizați"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Închideți"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Setări"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Trageți în jos pentru a închide"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meniu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
- <string name="pip_play" msgid="333995977693142810">"Redați"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Întrerupeți"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Treceți la următorul"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Treceți la cel anterior"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Redimensionați"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefonul s-a oprit din cauza încălzirii"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Acum telefonul funcționează normal"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Acum telefonul funcționează normal.\nAtingeți pentru mai multe informații"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonul se încălzise prea mult și s-a oprit pentru a se răci. Acum telefonul funcționează normal.\n\nTelefonul s-ar putea încălzi prea mult dacă:\n • folosiți aplicații care consumă multe resurse (de ex., jocuri, aplicații video/de navigare);\n • descărcați/încărcați fișiere mari;\n • folosiți telefonul la temperaturi ridicate."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vedeți pașii pentru îngrijire"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefonul se încălzește"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Anumite funcții sunt limitate în timp ce telefonul se răcește"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtingeți pentru mai multe informații"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonul va încerca automat să se răcească. Puteți folosi telefonul în continuare, dar este posibil să funcționeze mai lent.\n\nDupă ce se răcește, telefonul va funcționa normal."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Vedeți pașii pentru îngrijire"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Deconectați încărcătorul"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Există o problemă la încărcarea acestui dispozitiv. Deconectați adaptorul de curent și aveți grijă, deoarece cablul poate fi cald."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Vedeți pașii pentru îngrijire"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 8a2cdc911c17..12c489e08e41 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Изменить порядок быстрых настроек."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Страница <xliff:g id="ID_1">%1$d</xliff:g> из <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокированный экран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Развернуть"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Свернуть"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Закрыть"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Настройки"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Чтобы закрыть, потяните вниз"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Меню"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> находится в режиме \"Картинка в картинке\""</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Чтобы отключить эту функцию для приложения \"<xliff:g id="NAME">%s</xliff:g>\", перейдите в настройки."</string>
- <string name="pip_play" msgid="333995977693142810">"Воспроизвести"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Приостановить"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Перейти к следующему"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Перейти к предыдущему"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Изменить размер"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон выключился из-за перегрева"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Сейчас телефон работает нормально"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Сейчас телефон работает нормально.\nНажмите, чтобы получить дополнительную информацию"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ваш телефон выключился из-за перегрева. Сейчас он работает нормально.\n\nВозможные причины перегрева телефона:\n • использование ресурсоемких игр и приложений, связанных с видео или навигацией);\n • скачивание или загрузка больших файлов;\n • высокая температура окружающей среды."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Подробнее о действиях при перегреве…"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефон нагревается"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Пока телефон не остынет, некоторые функции могут быть недоступны."</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Пока телефон не остынет, некоторые функции могут быть недоступны.\nНажмите, чтобы получить дополнительную информацию"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон остынет автоматически.\n\nОбратите внимание, что до тех пор он может работать медленнее, чем обычно."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Подробнее о действиях при перегреве…"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Отключите зарядное устройство"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Во время зарядки возникла проблема. Отключите адаптер питания. Будьте осторожны, кабель может быть горячим."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Подробнее о действиях при перегреве…"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 0b35922d2c71..412050f4bb7f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"සැකසීම්වල අනුපිළිවෙළ සංංස්කරණය කරන්න."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g> න් <xliff:g id="ID_1">%1$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"අගුලු තිරය"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"දිග හරින්න"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"කුඩා කරන්න"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"වසන්න"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"සැකසීම්"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ඉවත ලෑමට පහළට ඇදගෙන යන්න"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"මෙනුව"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> පින්තූරය-තුළ-පින්තූරය තුළ වේ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"ඔබට <xliff:g id="NAME">%s</xliff:g> මෙම විශේෂාංගය භාවිත කිරීමට අවශ්‍ය නැති නම්, සැකසීම් විවෘත කිරීමට තට්ටු කර එය ක්‍රියාවිරහිත කරන්න."</string>
- <string name="pip_play" msgid="333995977693142810">"ධාවනය කරන්න"</string>
- <string name="pip_pause" msgid="1139598607050555845">"විරාම කරන්න"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ඊළඟ එකට පනින්න"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"පෙර එකට පනින්න"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ප්‍රතිප්‍රමාණ කරන්න"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"දුරකථනය රත් වීම නිසා ක්‍රියාවිරහිත කරන ලදී"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ඔබගේ දුරකථනය දැන් සාමාන්‍ය ලෙස ධාවනය වේ"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"ඔබගේ දුරකථනය දැන් සාමාන්‍ය ලෙස ධාවනය වේ.\nතව තතු සඳහා තට්ටු කරන්න"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"ඔබේ දුරකථනය ඉතාම උණුසුම්ය, එම නිසා එය සිසිල් වීමට ක්‍රියාවිරහිත කරන ලදී. ධැන් ඔබේ දුරකථනය සාමාන්‍ය පරිදි ධාවනය වේ.\n\nඔබ පහත දේවල් සිදු කළහොත් ඔබේ දුරකථනය ඉතාම උණුසුම් විය හැකිය:\n • සම්පත්-දැඩි සත්කාරක යෙදුම් භාවිතය (ක්‍රීඩා, වීඩියෝ, හෝ සංචලන යෙදුම් යනාදී)\n • විශාල ගොනු බාගැනීම හෝ උඩුගත කිරීම\n • ඔබේ දුරකථනය අධික උෂ්ණත්වයේදී භාවිත කිරීම"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"රැකවරණ පියවර බලන්න"</string>
<string name="high_temp_title" msgid="2218333576838496100">"දුරකථනය උණුසුම් වෙමින්"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"දුරකථනය සිසිල් වන අතරතුර සමහර විශේෂාංග සීමිත විය හැකිය.\nතව තතු සඳහා තට්ටු කරන්න"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"ඔබගේ දුරකථනය ස්වයංක්‍රියව සිසිල් වීමට උත්සාහ කරනු ඇත. ඔබට තවම ඔබේ දුරකථනය භාවිත කළ හැකිය, නමුත් එය සෙමින් ධාවනය විය හැකිය.\n\nඔබේ දුරකථනය සිසිල් වූ පසු, එය සාමාන්‍ය ලෙස ධාවනය වනු ඇත."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"රැකවරණ පියවර බලන්න"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"චාජරය පේනුවෙන් ඉවත් කරන්න"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"මෙම උපාංගය ආරෝපණ කිරීමේ ගැටලුවක් තිබේ බල ඇඩැප්ටරය ගලවා කේබලය උණුසුම් විය හැකි බැවින් පරෙස්සම් වන්න."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"රැකවරණ පියවර බලන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ab5a3885ae5f..f657d4fe71e7 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Upraviť poradie nastavení"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Strana <xliff:g id="ID_1">%1$d</xliff:g> z <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Uzamknutá obrazovka"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Rozbaliť"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimalizovať"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Zavrieť"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Nastavenia"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Zrušíte presunutím nadol"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Ponuka"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> je v režime obraz v obraze"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ak nechcete, aby aplikácia <xliff:g id="NAME">%s</xliff:g> používala túto funkciu, klepnutím otvorte nastavenia a vypnite ju."</string>
- <string name="pip_play" msgid="333995977693142810">"Prehrať"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pozastaviť"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Preskočiť na ďalšie"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Preskočiť na predchádzajúce"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Zmeniť veľkosť"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefón sa vypol z dôvodu prehriatia"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Teraz telefón funguje ako obvykle"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Teraz telefón funguje ako obvykle.\nViac sa dozviete po klepnutí."</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefón bol príliš horúci, preto sa vypol, aby vychladol. Teraz funguje ako obvykle.\n\nTelefón sa môže príliš zahriať v týchto prípadoch:\n • používanie náročných aplikácií (napr. hier, videí alebo navigácie);\n • sťahovanie alebo nahrávanie veľkých súborov;\n • používanie telefónu pri vysokých teplotách."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Zobraziť opatrenia"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Teplota telefónu stúpa"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Niektoré funkcie budú obmedzené, dokým neklesne teplota telefónu.\nViac sa dozviete po klepnutí."</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Váš telefón sa automaticky pokúsi schladiť. Môžete ho naďalej používať, ale môže fungovať pomalšie.\n\nPo poklese teploty bude telefón fungovať ako normálne."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Zobraziť opatrenia"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Odpojte nabíjačku"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Vyskytol sa problém s nabíjaním tohto zariadenia. Odpojte nabíjačku a postupujte opatrne, pretože kábel môže byť horúci."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Zobraziť opatrenia"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 1211944ef68b..1ae0209a45cd 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -940,11 +940,13 @@
<string name="pip_skip_to_prev" msgid="3742589641443049237">"Preskoči na prejšnjega"</string>
<string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Spremeni velikost"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Tel. izklopljen zaradi vročine"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Zdaj telefon normalno deluje"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefon zdaj deluje normalno.\nDotaknite se za več informacij"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon je bil prevroč, zato se je izklopil, da se ohladi. Zdaj normalno deluje.\n\nTelefon lahko postane prevroč ob:\n • uporabi aplikacij, ki intenzivno porabljajo sredstva (npr. za igranje iger, videoposnetke ali navigacijo)\n • prenosu ali nalaganju velikih datotek\n • uporabi telefona pri visokih temp."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Oglejte si navodila za ukrepanje"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon se segreva"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Nekatere funkcije bodo med ohlajanjem omejene."</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Nekatere funkcije bodo med ohlajanjem telefona omejene.\nDotaknite se za več informacij"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon se bo samodejno poskusil ohladiti. Še naprej ga lahko uporabljate, vendar bo morda deloval počasneje.\n\nKo se telefon ohladi, bo zopet deloval kot običajno."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Oglejte si navodila za ukrepanje"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Odklopite polnilnik"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Pri polnjenju te naprave je prišlo do težave. Previdno odklopite napajalnik, ker se je kabel morda segrel."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Oglejte si navodila za ukrepanje"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index b9300c4777d8..64d7a2ecac52 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Modifiko rendin e cilësimeve."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Faqja <xliff:g id="ID_1">%1$d</xliff:g> nga <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekrani i kyçjes"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Zgjero"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimizo"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Mbyll"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Cilësimet"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Zvarrit poshtë për të larguar"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menyja"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> është në figurë brenda figurës"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Nëse nuk dëshiron që <xliff:g id="NAME">%s</xliff:g> ta përdorë këtë funksion, trokit për të hapur cilësimet dhe për ta çaktivizuar."</string>
- <string name="pip_play" msgid="333995977693142810">"Luaj"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Ndërprit"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Kalo te tjetra"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Kalo tek e mëparshmja"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ndrysho përmasat"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefoni u fik për shkak të nxehtësisë"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefoni tani punon normalisht"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefoni tani punon normalisht.\nTrokit për më shumë informacione"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefoni yt ishte tepër i nxehtë, prandaj u fik për t\'u ftohur. Telefoni tani punon normalisht.\n\nTelefoni mund të nxehet së tepërmi nëse ti:\n • Përdor aplikacione intensive për burimet (siç janë aplikacionet e lojërave, videove apo aplikacionet e navigimit)\n • Shkarkon ose ngarkon skedarë të mëdhenj\n • E përdor telefonin në temperatura të larta"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Shiko hapat për kujdesin"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefoni po bëhet i ngrohtë"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Disa funksione janë të kufizuara kur telefoni është duke u ftohur"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Disa veçori janë të kufizuara kur telefoni është duke u ftohur.\nTrokit për më shumë informacione"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Shiko hapat për kujdesin"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Shkëput karikuesin"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Ka një problem me karikimin e kësaj pajisjeje. Hiqe spinën dhe trego kujdes pasi kablloja mund të jetë e ngrohtë."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Shiko hapat për kujdesin"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a01ee85ff11d..fd6f57e64113 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -921,25 +921,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Измени редослед подешавања."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>. страна од <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Закључан екран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Прошири"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Умањи"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Затвори"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Подешавања"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Превуците надоле да бисте одбили"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Мени"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> је слика у слици"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ако не желите да <xliff:g id="NAME">%s</xliff:g> користи ову функцију, додирните да бисте отворили подешавања и искључили је."</string>
- <string name="pip_play" msgid="333995977693142810">"Пусти"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Паузирај"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Пређи на следеће"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Пређи на претходно"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Промените величину"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон се искључио због топлоте"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Телефон сада нормално ради"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Телефон сада нормално ради.\nДодирните за више информација"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефон је био преврућ, па се искључио да се охлади. Сада ради нормално.\n\nТелефон може превише да се угреје ако:\n • Користите апликације које захтевају пуно ресурса (нпр. видео игре, видео или апликације за навигацију)\n • Преузимате/отпремате велике датотеке\n • Користите телефон на високој температури"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Погледајте упозорења"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефон се загрејао"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Неке функције су ограничене док се телефон не охлади"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Неке функције су ограничене док се телефон не охлади.\nДодирните за више информација"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Телефон ће аутоматски покушати да се охлади. И даље ћете моћи да користите телефон, али ће спорије реаговати.\n\nКада се телефон охлади, нормално ће радити."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Погледајте упозорења"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Искључите пуњач из напајања"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Дошло је до проблема са пуњењем овог уређаја. Искључите адаптер из напајања и будите пажљиви јер кабл може да буде топао."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Погледајте упозорења"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 9b1ab7f4b342..f96dd27aba6d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ändra ordning på inställningarna."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sida <xliff:g id="ID_1">%1$d</xliff:g> av <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Låsskärm"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Utöka"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Minimera"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Stäng"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Inställningar"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Tryck och dra nedåt för att ta bort"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Meny"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> visas i bild-i-bild"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Om du inte vill att den här funktionen används i <xliff:g id="NAME">%s</xliff:g> öppnar du inställningarna genom att trycka. Sedan inaktiverar du funktionen."</string>
- <string name="pip_play" msgid="333995977693142810">"Spela upp"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pausa"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Hoppa till nästa"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Hoppa till föregående"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Ändra storlek"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Mobilen stängdes av pga. värme"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Mobilen fungerar nu som vanligt"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonen fungerar nu som vanligt.\nTryck för mer information"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Mobilen var för varm och stängdes av för att kylas ned. Den fungerar nu som vanligt.\n\nMobilen kan bli för varm om du\n • använder resurskrävande appar (till exempel spel-, video- eller navigeringsappar)\n • laddar ned eller laddar upp stora filer\n • använder mobilen vid höga temperaturer."</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Visa alla skötselråd"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Mobilen börjar bli varm"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Vissa funktioner är begränsade medan mobilen svalnar"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Vissa funktioner är begränsade medan telefonen svalnar.\nTryck för mer information"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Mobilen försöker svalna automatiskt. Du kan fortfarande använda mobilen, men den kan vara långsammare än vanligt.\n\nMobilen fungerar som vanligt när den har svalnat."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Visa alla skötselråd"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Koppla ur laddaren"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Det går inte att ladda denna enhet. Koppla ur nätadaptern, men var försiktig eftersom kabeln kan vara varm."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Visa alla skötselråd"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 512200976263..8b8c24983e98 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Badilisha orodha ya mipangilio."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ukurasa wa <xliff:g id="ID_1">%1$d</xliff:g> kati ya <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Skrini iliyofungwa"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Panua"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Punguza"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Funga"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Mipangilio"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Buruta ili uondoe"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menyu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> iko katika hali ya picha ndani ya picha nyingine"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Ikiwa hutaki <xliff:g id="NAME">%s</xliff:g> itumie kipengele hiki, gusa ili ufungue mipangilio na uizime."</string>
- <string name="pip_play" msgid="333995977693142810">"Cheza"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Sitisha"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Ruka ufikie inayofuata"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Ruka ufikie iliyotangulia"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Badilisha ukubwa"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Simu ilizima kutokana na joto"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Simu yako sasa inafanya kazi ipasavyo"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Simu yako sasa inafanya kazi ipasavyo.\nGusa ili upate maelezo zaidi"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Simu yako ilikuwa moto sana, kwa hivyo ilijizima ili ipoe. Simu yako sasa inafanya kazi ipasavyo.\n\nSimu yako inaweza kuwa moto sana ikiwa:\n • Unatumia programu zinazotumia vipengee vingi (kama vile michezo ya video, video au programu za uelekezaji)\n • Unapakua au upakie faili kubwa\n • Unatumia simu yako katika maeneo yenye halijoto ya juu"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Angalia hatua za utunzaji"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Joto la simu linaongezeka"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Baadhi ya vipengele havitatumika kwenye simu wakati inapoa.\nGusa ili upate maelezo zaidi"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Simu yako itajaribu kupoa kiotomatiki. Bado unaweza kutumia simu yako, lakini huenda ikafanya kazi polepole. \n\nPindi simu yako itakapopoa, itaendelea kufanya kazi kama kawaida."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Angalia hatua za utunzaji"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Chomoa chaja"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kuna tatizo la kuchaji kifaa hiki. Chomoa adapta ya nishati na uwe mwangalifu, huenda kebo ni moto."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Angalia hatua za ulinzi"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index b757fb00cffb..b97e266850c6 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"அமைப்புகளின் வரிசை முறையைத் திருத்து."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"பக்கம் <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"லாக் ஸ்கிரீன்"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"விரி"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"சிறிதாக்கு"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"மூடு"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"அமைப்புகள்"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"நிராகரிக்க, கீழே இழுக்கவும்"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"மெனு"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> தற்போது பிக்ச்சர்-இன்-பிக்ச்சரில் உள்ளது"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> இந்த அம்சத்தைப் பயன்படுத்த வேண்டாம் என நினைத்தால் இங்கு தட்டி அமைப்புகளைத் திறந்து இதை முடக்கவும்."</string>
- <string name="pip_play" msgid="333995977693142810">"இயக்கு"</string>
- <string name="pip_pause" msgid="1139598607050555845">"இடைநிறுத்து"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"அடுத்ததற்குச் செல்"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"முந்தையதற்குச் செல்"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"அளவு மாற்று"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"வெப்பத்தினால் ஃபோன் ஆஃப் செய்யப்பட்டது"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"இப்போது உங்கள் மொபைல் இயல்புநிலையில் இயங்குகிறது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"உங்கள் ஃபோன் அதிகமாகச் சூடானதால், அதன் சூட்டைக் குறைக்க, ஆஃப் செய்யப்பட்டது. இப்போது உங்கள் ஃபோன் இயல்புநிலையில் இயங்குகிறது.\n\nபின்வருவனவற்றைச் செய்தால், ஃபோன் சூடாகலாம்:\n • அதிகளவு தரவைப் பயன்படுத்தும் ஆப்ஸை (எ.கா: கேமிங், வீடியோ (அ) வழிகாட்டுதல் ஆப்ஸ்) பயன்படுத்துவது\n • பெரிய கோப்புகளைப் பதிவிறக்குவது/பதிவேற்றுவது\n • அதிக வெப்பநிலையில் ஃபோனைப் பயன்படுத்துவது"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
<string name="high_temp_title" msgid="2218333576838496100">"மொபைல் சூடாகிறது"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"மொபைலின் வெப்ப அளவு குறையும் போது, சில அம்சங்களைப் பயன்படுத்த முடியாது"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"மொபைலின் வெப்ப அளவு குறையும் வரை சில அம்சங்களைப் பயன்படுத்த முடியாது.\nமேலும் தகவலுக்கு தட்டவும்"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"உங்கள் மொபைலின் வெப்ப அளவு தானாகவே குறையும். தொடர்ந்து நீங்கள் மொபைலைப் பயன்படுத்தலாம், ஆனால் அதன் வேகம் குறைவாக இருக்கக்கூடும்.\n\nமொபைலின் வெப்ப அளவு குறைந்தவுடன், அது இயல்பு நிலையில் இயங்கும்."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"சார்ஜரைத் துண்டிக்கவும்"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"இந்தச் சாதனத்தைச் சார்ஜ் செய்வதில் சிக்கல் உள்ளது. பவர் அடாப்டரைத் துண்டிக்கவும், கேபிள் சூடாக இருக்கக்கூடும் என்பதால் கவனமாகக் கையாளவும்."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"மேலும் விவரங்களுக்கு இதைப் பார்க்கவும்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index ccca95dd5ba3..49c9af1bad48 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"సెట్టింగ్‌ల క్రమాన్ని సవరించండి."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_2">%2$d</xliff:g>లో <xliff:g id="ID_1">%1$d</xliff:g>వ పేజీ"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"లాక్ స్క్రీన్"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"విస్తరింపజేయి"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"కనిష్టీకరించు"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"మూసివేయి"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"సెట్టింగ్‌లు"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"తీసివేయడానికి కిందికి లాగండి"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"మెను"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> చిత్రంలో చిత్రం రూపంలో ఉంది"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ఈ లక్షణాన్ని ఉపయోగించకూడదు అని మీరు అనుకుంటే, సెట్టింగ్‌లను తెరవడానికి ట్యాప్ చేసి, దీన్ని ఆఫ్ చేయండి."</string>
- <string name="pip_play" msgid="333995977693142810">"ప్లే చేయి"</string>
- <string name="pip_pause" msgid="1139598607050555845">"పాజ్ చేయి"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"పరిమాణం మార్చు"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"వేడెక్కినందుకు ఫోన్ ఆఫ్ చేయబడింది"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"మీ ఫోన్ చాలా వేడిగా ఉంది, కనుక చల్లబర్చడానికి ఆఫ్ చేయబడింది. మీ ఫోన్ ఇప్పుడు సాధారణంగా పని చేస్తుంది.\n\nమీరు ఇలా చేస్తే మీ ఫోన్ చాలా వేడెక్కవచ్చు:\n • వనరు-ఆధారిత అనువర్తనాలు (గేమింగ్, వీడియో లేదా నావిగేషన్ వంటి అనువర్తనాలు) ఉపయోగించడం\n • పెద్ద ఫైల్‌లను డౌన్‌లోడ్ లేదా అప్‌లోడ్ చేయడం\n • అధిక ఉష్ణోగ్రతలలో మీ ఫోన్‌ని ఉపయోగించడం"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"ఫోన్ వేడెక్కుతోంది"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ఫోన్‌ను చల్లబరిచే క్రమంలో కొన్ని లక్షణాలు పరిమితం చేయబడ్డాయి"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"మీ ఫోన్ స్వయంచాలకంగా చల్లబడటానికి ప్రయత్నిస్తుంది. మీరు ఇప్పటికీ మీ ఫోన్‌ను ఉపయోగించవచ్చు, కానీ దాని పనితీరు నెమ్మదిగా ఉండవచ్చు.\n\nమీ ఫోన్ చల్లబడిన తర్వాత, అది సాధారణ రీతిలో పని చేస్తుంది."</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ప్లగ్ నుండి ఛార్జర్‌ తీసివేయండి"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"ఈ పరికరాన్ని ఛార్జ్ చేయడంలో సమస్య ఉంది. పవర్ అడాప్టర్‌ను ప్లగ్ నుండి తీసివేసి, కేబుల్ ఏమైనా వేడిగా అయితే తగిన జాగ్రత్తలు తీసుకోండి."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"తీసుకోవాల్సిన జాగ్రత్తలు ఏమిటో చూడండి"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 514481ee8b7b..e1c0e7e7a614 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"แก้ไขลำดับการตั้งค่า"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"หน้า <xliff:g id="ID_1">%1$d</xliff:g> จาก <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"หน้าจอล็อก"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"ขยาย"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"ย่อเล็กสุด"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"ปิด"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"การตั้งค่า"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"ลากลงเพื่อปิด"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"เมนู"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> ใช้การแสดงภาพซ้อนภาพ"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"หากคุณไม่ต้องการให้ <xliff:g id="NAME">%s</xliff:g> ใช้ฟีเจอร์นี้ ให้แตะเพื่อเปิดการตั้งค่าแล้วปิดฟีเจอร์"</string>
- <string name="pip_play" msgid="333995977693142810">"เล่น"</string>
- <string name="pip_pause" msgid="1139598607050555845">"หยุดชั่วคราว"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"ข้ามไปรายการถัดไป"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"ข้ามไปรายการก่อนหน้า"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"ปรับขนาด"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"โทรศัพท์ปิดไปเพราะร้อนมาก"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"ขณะนี้โทรศัพท์ทำงานเป็นปกติ"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"ขณะนี้โทรศัพท์ทำงานเป็นปกติ\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"โทรศัพท์ร้อนเกินไปจึงปิดเครื่องเพื่อให้เย็นลง ขณะนี้โทรศัพท์ทำงานเป็นปกติ\n\nโทรศัพท์อาจร้อนเกินไปหากคุณ\n • ใช้แอปที่ใช้ทรัพยากรมาก (เช่น เกม วิดีโอ หรือแอปการนำทาง)\n • ดาวน์โหลดหรืออัปโหลดไฟล์ขนาดใหญ่\n • ใช้โทรศัพท์ในอุณหภูมิที่สูง"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"ดูขั้นตอนในการดูแลรักษา"</string>
<string name="high_temp_title" msgid="2218333576838496100">"โทรศัพท์เริ่มเครื่องร้อน"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์ลดอุณหภูมิลง"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"ฟีเจอร์บางอย่างจะใช้งานได้จำกัดขณะโทรศัพท์เย็นลง\nแตะเพื่อดูข้อมูลเพิ่มเติม"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"โทรศัพท์จะพยายามลดอุณหภูมิลงโดยอัตโนมัติ คุณยังสามารถใช้โทรศัพท์ได้ แต่โทรศัพท์อาจทำงานช้าลง\n\nโทรศัพท์จะทำงานตามปกติเมื่อเย็นลงแล้ว"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"ดูขั้นตอนในการดูแลรักษา"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"ถอดปลั๊กที่ชาร์จ"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"พบปัญหาในการชาร์จอุปกรณ์นี้ ถอดปลั๊กอะแดปเตอร์ด้วยความระมัดระวังเพราะสายอาจร้อน"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"ดูขั้นตอนในการดูแลรักษา"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f743fd34e4ea..20a34e1ded0d 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"I-edit ang pagkakasunud-sunod ng mga setting."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Page <xliff:g id="ID_1">%1$d</xliff:g> ng <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Lock screen"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Palawakin"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"I-minimize"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Isara"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Mga Setting"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"I-drag pababa upang i-dismiss"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"Nasa picture-in-picture ang <xliff:g id="NAME">%s</xliff:g>"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Kung ayaw mong magamit ni <xliff:g id="NAME">%s</xliff:g> ang feature na ito, i-tap upang buksan ang mga setting at i-off ito."</string>
- <string name="pip_play" msgid="333995977693142810">"I-play"</string>
- <string name="pip_pause" msgid="1139598607050555845">"I-pause"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Lumaktaw sa susunod"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Lumaktaw sa nakaraan"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"I-resize"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Na-off ang telepono dahil sa init"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Maayos na ngayong gumagana ang iyong telepono"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Maayos na ngayong gumagana ang iyong telepono.\nMag-tap para sa higit pang impormasyon"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Napakainit ng telepono, kaya nag-off ito para lumamig. Maayos na itong gumagana.\n\nMaaaring lubos na uminit ang telepono kapag:\n • Gumamit ka ng resource-intensive na app (gaya ng app para sa gaming, video, o navigation)\n • Nag-download o nag-upload ka ng malaking file\n • Ginamit mo ito sa mainit na lugar"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Tingnan ang mga hakbang sa pangangalaga"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Umiinit ang telepono"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Limitado ang ilang feature habang nagku-cool down ang telepono"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Limitado ang ilang feature habang nagku-cool down ang telepono.\nMag-tap para sa higit pang impormasyon"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Awtomatikong susubukan ng iyong telepono na mag-cool down. Magagamit mo pa rin ang iyong telepono, ngunit maaaring mas mabagal ang paggana nito.\n\nKapag nakapag-cool down na ang iyong telepono, gagana na ito nang normal."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Tingnan ang mga hakbang sa pangangalaga"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Hugutin ang charger"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"May isyu sa pag-charge ng device na ito. Hugutin ang power adapter at mag-ingat dahil maaaring mainit ang cable."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Tingnan ang mga hakbang sa pangangalaga"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index a1e5cee90657..4146f307ac18 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Ayarların sırasını düzenle."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Sayfa <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Kilit ekranı"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Genişlet"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Simge durumuna getir"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Kapat"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Ayarlar"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Kapatmak için aşağıya sürükleyin"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menü"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g>, pencere içinde pencere özelliğini kullanıyor"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> uygulamasının bu özelliği kullanmasını istemiyorsanız dokunarak ayarları açın ve söz konusu özelliği kapatın."</string>
- <string name="pip_play" msgid="333995977693142810">"Oynat"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Duraklat"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Sonrakine atla"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Öncekine atla"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Yeniden boyutlandır"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Telefon ısındığından kapatıldı"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefonunuz şu anda normal bir şekilde çalışıyor"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Telefonunuz şu anda normal bir şekilde çalışıyor.\nDaha fazla bilgi için dokunun"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonunuz çok ısındığından soğuması için kapatıldı ve şu anda normal bir şekilde çalışıyor.\n\nTelefon şu koşullarda çok ısınabilir:\n • Yoğun kaynak gerektiren uygulamalar (oyun, video veya gezinme uygulamaları gibi) kullanma\n • Büyük dosyalar indirme veya yükleme\n • Telefonu sıcak yerlerde kullanma"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bakımla ilgili adımlara bakın"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon ısınıyor"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon soğurken bazı özellikler sınırlı olarak kullanılabilir.\nDaha fazla bilgi için dokunun"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonunuz otomatik olarak soğumaya çalışacak. Bu sırada telefonunuzu kullanmaya devam edebilirsiniz ancak uygulamalar daha yavaş çalışabilir.\n\nTelefonunuz soğuduktan sonra normal şekilde çalışacaktır."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bakımla ilgili adımlara bakın"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Şarj cihazını çıkarın"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu cihaz şarj edilirken bir sorun oluştu. Güç adaptörünün fişini çekin. Kablo sıcak olabileceğinden fişi çekerken dikkatli olun."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bakımla ilgili adımlara bakın"</string>
diff --git a/packages/SystemUI/res/values-tvdpi/dimens.xml b/packages/SystemUI/res/values-tvdpi/dimens.xml
index 4d978aacc65f..5327cee7cae8 100644
--- a/packages/SystemUI/res/values-tvdpi/dimens.xml
+++ b/packages/SystemUI/res/values-tvdpi/dimens.xml
@@ -24,8 +24,4 @@
<fraction name="battery_subpixel_smoothing_right">10%</fraction>
<dimen name="battery_margin_bottom">1px</dimen>
-
- <!-- The dimensions to user for picture-in-picture action buttons. -->
- <dimen name="picture_in_picture_button_width">100dp</dimen>
- <dimen name="picture_in_picture_button_start_margin">-50dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index d5c6e253fcc3..66df805a2a2f 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -926,25 +926,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Змінити порядок налаштувань."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Сторінка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Заблокований екран"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Розгорнути"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Згорнути"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Закрити"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Налаштування"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Перетягніть униз, щоб закрити"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Меню"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"У додатку <xliff:g id="NAME">%s</xliff:g> є функція \"Картинка в картинці\""</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Щоб додаток <xliff:g id="NAME">%s</xliff:g> не використовував цю функцію, вимкніть її в налаштуваннях."</string>
- <string name="pip_play" msgid="333995977693142810">"Відтворити"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Призупинити"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Перейти далі"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Перейти назад"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Змінити розмір"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Телефон перегрівся й вимкнувся"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Зараз телефон працює, як зазвичай"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Зараз телефон працює як зазвичай.\nНатисніть, щоб дізнатися більше"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Телефон перегрівся, тому вимкнувся, щоб охолонути. Зараз він працює, як зазвичай.\n\nТелефон перегрівається, якщо ви:\n • використовуєте ресурсомісткі додатки (ігри, відео, навігація)\n • завантажуєте великі файли на телефон або з нього\n • використовуєте телефон за високої температури"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Переглянути застереження"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Телефон нагрівається"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Під час охолодження деякі функції обмежуються"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Під час охолодження деякі функції обмежуються.\nНатисніть, щоб дізнатися більше"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ваш телефон охолоджуватиметься автоматично. Ви можете далі користуватися телефоном, але він може працювати повільніше.\n\nКоли телефон охолоне, він працюватиме належним чином."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Переглянути застереження"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Відключіть зарядний пристрій"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Виникла проблема із заряджанням пристрою. Відключіть адаптер живлення, однак будьте обережні, оскільки кабель може бути гарячим."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Переглянути застереження"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index cb73ccdfb277..b740d22921dc 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -916,25 +916,18 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"ترتیبات کی ترتیب میں ترمیم کریں۔"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"صفحہ <xliff:g id="ID_1">%1$d</xliff:g> از <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"مقفل اسکرین"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"پھیلائیں"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"چھوٹی کریں"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"بند کریں"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"ترتیبات"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"برخاست کرنے کیلئے نیچے گھسیٹیں"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"مینو"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> تصویر میں تصویر میں ہے"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"اگر آپ نہیں چاہتے ہیں کہ <xliff:g id="NAME">%s</xliff:g> اس خصوصیت کا استعمال کرے تو ترتیبات کھولنے کے لیے تھپتھپا کر اسے آف کرے۔"</string>
- <string name="pip_play" msgid="333995977693142810">"چلائیں"</string>
- <string name="pip_pause" msgid="1139598607050555845">"موقوف کریں"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"نظرانداز کرکے اگلے پر جائیں"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"نظرانداز کرکے پچھلے پر جائیں"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"سائز تبدیل کریں"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"حرارت کی وجہ سے فون آف ہو گیا"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"آپ کا فون اب حسب معمول کام کر رہا ہے"</string>
+ <!-- no translation found for thermal_shutdown_message (6142269839066172984) -->
+ <skip />
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"آپ کا فون کافی گرم ہو گيا تھا، اس لئے سرد ہونے کیلئے یہ آف ہو گیا۔ اب آپ کا فون حسب معمول کام کر رہا ہے۔\n\nمندرجہ ذیل چیزیں کرنے پر آپ کا فون کافی گرم ہو سکتا ہے:\n • ماخذ کا زیادہ استعمال کرنے والی ایپس (جیسے کہ گیمنگ، ویڈیو، یا نیویگیشن ایپس) کا استعمال کرنا\n • بڑی فائلز ڈاؤن لوڈ یا اپ لوڈ کرنا\n • اعلی درجہ حرارت میں فون کا استعمال کرنا"</string>
+ <!-- no translation found for thermal_shutdown_dialog_help_text (6413474593462902901) -->
+ <skip />
<string name="high_temp_title" msgid="2218333576838496100">"فون گرم ہو رہا ہے"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"فون کے ٹھنڈے ہو جانے تک کچھ خصوصیات محدود ہیں"</string>
+ <!-- no translation found for high_temp_notif_message (1277346543068257549) -->
+ <skip />
<string name="high_temp_dialog_message" msgid="3793606072661253968">"آپ کا فون خودکار طور پر ٹھنڈا ہونے کی کوشش کرے گا۔ آپ ابھی بھی اپنا فون استعمال کر سکتے ہیں، مگر ہو سکتا ہے یہ سست چلے۔\n\nایک بار آپ کا فون ٹھنڈا ہوجائے تو یہ معمول کے مطابق چلے گا۔"</string>
+ <!-- no translation found for high_temp_dialog_help_text (7380171287943345858) -->
+ <skip />
<string name="high_temp_alarm_title" msgid="2359958549570161495">"چارجر ان پلگ کریں"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"اس آلہ کو چارج کرنے میں ایک مسئلہ ہے۔ پاور ایڈاپٹر کو ان پلگ کریں اور دھیان دیں کیونکہ تار گرم ہو سکتا ہے۔"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"نگہداشت کے اقدامات ملاحظہ کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 63b0888f3c3b..1fc4f9bea270 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Sozlamalar tartibini o‘zgartirish."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"<xliff:g id="ID_1">%1$d</xliff:g>-sahifa, jami: <xliff:g id="ID_2">%2$d</xliff:g> ta sahifa"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Ekran qulfi"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Yoyish"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Yig‘ish"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Yopish"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Sozlamalar"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Yopish uchun pastga torting"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menyu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> tasvir ustida tasvir rejimida"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"<xliff:g id="NAME">%s</xliff:g> ilovasi uchun bu funksiyani sozlamalar orqali faolsizlantirish mumkin."</string>
- <string name="pip_play" msgid="333995977693142810">"Ijro"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Pauza"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Keyingisiga o‘tish"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Avvalgisiga qaytish"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Oʻlchamini oʻzgartirish"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Qizigani uchun o‘chirildi"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Telefoningiz hozir normal holatda ishlayapti"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Endi telefoningiz normal holatda ishlayapti.\nBatafsil axborot uchun bosing"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefon qizib ketganligi sababli sovitish uchun o‘chirib qo‘yilgan. Endi telefoningiz normal holatda ishlayapti.\n\nTelefon bu hollarda qizib ketishi mumkin:\n • Resurstalab ilovalar ishlatilganda (masalan, o‘yin, video yoki navigatsiya ilovalari)\n • Katta faylni yuklab olishda yoki yuklashda\n • Telefondan yuqori haroratda foydalanganda"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Batafsil axborot"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Telefon qizib ketdi"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Telefon sovish paytida ayrim funksiyalar ishlamasligi mumkin"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Telefon sovib qolganda ayrim funksiyalari ishlamasligi mumkin.\nBatafsil axborot uchun bosing"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefon avtomatik ravishda o‘zini sovitadi. Telefoningizdan foydalanishda davom etishingiz mumkin, lekin u sekinroq ishlashi mumkin.\n\nTelefon sovishi bilan normal holatda ishlashni boshlaydi."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Batafsil axborot"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Quvvatlash moslamasini uzing"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Bu qurilmani quvvatlashda muammo bor. Quvvat adapteri va kabelni tarmoqdan uzing, ular qizib ketgan boʻlishi mumkin."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Batafsil axborot"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 1c25e97f58dd..8df5ee530210 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Chỉnh sửa thứ tự cài đặt."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Trang <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Màn hình khóa"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Mở rộng"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Thu nhỏ"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Đóng"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Cài đặt"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Kéo xuống để loại bỏ"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Menu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g> đang ở chế độ ảnh trong ảnh"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Nếu bạn không muốn <xliff:g id="NAME">%s</xliff:g> sử dụng tính năng này, hãy nhấn để mở cài đặt và tắt tính năng này."</string>
- <string name="pip_play" msgid="333995977693142810">"Phát"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Tạm dừng"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Chuyển tới mục tiếp theo"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Chuyển về mục trước"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Đổi kích thước"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Điện thoại đã tắt do nhiệt"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Điện thoại của bạn hiện đang chạy bình thường"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Điện thoại của bạn đang chạy bình thường.\nHãy nhấn để biết thêm thông tin"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Do quá nóng nên điện thoại đã tắt để hạ nhiệt. Hiện điện thoại của bạn đang chạy bình thường.\n\nĐiện thoại có thể bị quá nóng nếu bạn:\n • Dùng các ứng dụng tốn nhiều tài nguyên (như ứng dụng trò chơi, video hoặc điều hướng)\n • Tải xuống hoặc tải lên tệp có dung lượng lớn\n • Dùng điện thoại ở nhiệt độ cao"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Xem các bước chăm sóc"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Điện thoại đang nóng lên"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Một số tính năng bị hạn chế trong khi điện thoại nguội dần.\nHãy nhấn để biết thêm thông tin"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Điện thoại của bạn sẽ tự động nguội dần. Bạn vẫn có thể sử dụng điện thoại, nhưng điện thoại có thể chạy chậm hơn. \n\nSau khi đã nguội, điện thoại sẽ chạy bình thường."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Xem các bước chăm sóc"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Rút phích cắm bộ sạc"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Đã xảy ra sự cố khi sạc thiết bị này. Hãy rút phích cắm bộ chuyển đổi điện và cẩn thận vì dây cáp có thể nóng."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Xem các bước chăm sóc"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index d127d1760825..c51982cddac3 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"修改设置顺序。"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 页,共 <xliff:g id="ID_2">%2$d</xliff:g> 页"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"锁定屏幕"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"展开"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"最小化"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"关闭"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"设置"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"向下拖动即可关闭"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"菜单"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"<xliff:g id="NAME">%s</xliff:g>目前位于“画中画”中"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"如果您不想让“<xliff:g id="NAME">%s</xliff:g>”使用此功能,请点按以打开设置,然后关闭此功能。"</string>
- <string name="pip_play" msgid="333995977693142810">"播放"</string>
- <string name="pip_pause" msgid="1139598607050555845">"暂停"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"跳到下一个"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"跳到上一个"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"调整大小"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"手机因严重发热而自动关机"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"现在,您的手机已恢复正常运行"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"现在,您的手机已恢复正常运行。\n点按即可了解详情"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"由于发热严重,因此您的手机执行了自动关机以降温。现在,您的手机已恢复正常运行。\n\n以下情况可能会导致您的手机严重发热:\n • 使用占用大量资源的应用(例如游戏、视频或导航应用)\n • 下载或上传大型文件\n • 在高温环境下使用手机"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看处理步骤"</string>
<string name="high_temp_title" msgid="2218333576838496100">"手机温度上升中"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"手机降温时,部分功能的使用会受限制"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"手机降温时,部分功能的使用会受限制。\n点按即可了解详情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"您的手机将自动尝试降温。您依然可以使用您的手机,但是手机运行速度可能会更慢。\n\n手机降温后,就会恢复正常的运行速度。"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看处理步骤"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充电器"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"为此设备充电时出现问题。这可能是由数据线太热所导致,请拔下电源适配器并采取相应的处理措施。"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看处理步骤"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index ffbf12d5ae2c..aa9945fbd956 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定次序。"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁 (共 <xliff:g id="ID_2">%2$d</xliff:g> 頁)"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"螢幕鎖定"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"展開"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"最小化"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"關閉"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"設定"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"向下拖曳即可關閉"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"選單"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"「<xliff:g id="NAME">%s</xliff:g>」目前在畫中畫模式"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"如果您不想「<xliff:g id="NAME">%s</xliff:g>」使用此功能,請輕按以開啟設定,然後停用此功能。"</string>
- <string name="pip_play" msgid="333995977693142810">"播放"</string>
- <string name="pip_pause" msgid="1139598607050555845">"暫停"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"跳到下一個"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"跳到上一個"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"調整大小"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"手機因過熱而關上"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"您的手機現已正常運作"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"您的手機現已正常運作。\n輕按即可瞭解詳情"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"您的手機之前因過熱而關上降溫。手機現已正常運作。\n\n以下情況可能會導致手機過熱:\n • 使用耗用大量資源的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上載大型檔案\n • 在高溫環境下使用手機"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看保養步驟"</string>
<string name="high_temp_title" msgid="2218333576838496100">"手機溫度正在上升"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"手機降溫時,部分功能會受限制"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,部分功能會受限制。\n輕按即可瞭解詳情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。您仍可以使用手機,但手機的運作速度可能較慢。\n\n手機降溫後便會恢復正常。"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看保養步驟"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"拔下充電器"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為此裝置充電時發生問題。請拔除電源適配器並注意安全,因為連接線可能會發熱。"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看保養步驟"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d52e247f9434..92bdfc3f1219 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"編輯設定順序。"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"第 <xliff:g id="ID_1">%1$d</xliff:g> 頁,共 <xliff:g id="ID_2">%2$d</xliff:g> 頁"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"鎖定畫面"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"展開"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"最小化"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"關閉"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"設定"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"向下拖曳即可關閉"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"選單"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"「<xliff:g id="NAME">%s</xliff:g>」目前在子母畫面中"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"如果你不想讓「<xliff:g id="NAME">%s</xliff:g>」使用這項功能,請輕觸開啟設定頁面,然後停用此功能。"</string>
- <string name="pip_play" msgid="333995977693142810">"播放"</string>
- <string name="pip_pause" msgid="1139598607050555845">"暫停"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"跳到下一個"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"跳到上一個"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"調整大小"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"手機先前過熱,因此關閉電源"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"手機現在已恢復正常運作"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"手機現在已恢復正常運作。\n輕觸即可瞭解詳情"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"手機先前的溫度過高,因此關閉了電源以進行降溫。手機現在已恢復正常運作。\n\n以下情況可能會導致你的手機溫度過高:\n • 使用需要密集處理資料的應用程式 (例如遊戲、影片或導航應用程式)\n • 下載或上傳大型檔案\n • 在高溫環境下使用手機"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"查看處理步驟"</string>
<string name="high_temp_title" msgid="2218333576838496100">"手機變熱"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"手機降溫時,部分功能會受限"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"手機降溫時,某些功能會受限。\n輕觸即可瞭解詳情"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"手機會自動嘗試降溫。你仍可繼續使用手機,但是手機的運作速度可能會較慢。\n\n手機降溫完畢後,就會恢復正常的運作速度。"</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"查看處理步驟"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"拔除充電器"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"為這個裝置充電時發生問題。這可能是因為傳輸線過熱所致,請拔除電源變壓器並採取處理措施。"</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"查看處理步驟"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f379bf37a80f..4ae126799141 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -916,25 +916,14 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Hlela uhlelo lwezilungiselelo."</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Ikhasi <xliff:g id="ID_1">%1$d</xliff:g> kwangu-<xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Khiya isikrini"</string>
- <string name="pip_phone_expand" msgid="1424988917240616212">"Nweba"</string>
- <string name="pip_phone_minimize" msgid="9057117033655996059">"Nciphisa"</string>
- <string name="pip_phone_close" msgid="8801864042095341824">"Vala"</string>
- <string name="pip_phone_settings" msgid="5687538631925004341">"Izilungiselelo"</string>
- <string name="pip_phone_dismiss_hint" msgid="5825740708095316710">"Hudulela phansi ukuze ucashise"</string>
- <string name="pip_menu_title" msgid="6365909306215631910">"Imenyu"</string>
- <string name="pip_notification_title" msgid="8661573026059630525">"U-<xliff:g id="NAME">%s</xliff:g> ungaphakathi kwesithombe esiphakathi kwesithombe"</string>
- <string name="pip_notification_message" msgid="4991831338795022227">"Uma ungafuni i-<xliff:g id="NAME">%s</xliff:g> ukuthi isebenzise lesi sici, thepha ukuze uvule izilungiselelo uphinde uyivale."</string>
- <string name="pip_play" msgid="333995977693142810">"Dlala"</string>
- <string name="pip_pause" msgid="1139598607050555845">"Misa isikhashana"</string>
- <string name="pip_skip_to_next" msgid="3864212650579956062">"Yeqela kokulandelayo"</string>
- <string name="pip_skip_to_prev" msgid="3742589641443049237">"Yeqela kokwangaphambilini"</string>
- <string name="accessibility_action_pip_resize" msgid="8237306972921160456">"Shintsha usayizi"</string>
<string name="thermal_shutdown_title" msgid="2702966892682930264">"Ifoni ivaliwe ngenxa yokushisa"</string>
- <string name="thermal_shutdown_message" msgid="7432744214105003895">"Ifoni yakho manje isebenza kahle"</string>
+ <string name="thermal_shutdown_message" msgid="6142269839066172984">"Ifoni yakho manje isebenza ngokuvamile.\nThepha ukuze uthole ulwazi olungeziwe"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ifoni yakho ibishisa kakhulu, ngakho-ke yacisha ukuze iphole. Ifoni yakho manje isebenza ngokuvamile.\n\nIfoni yakho ingashisa kakhulu uma:\n • Usebenzisa izinhlelo zokusebenza ezinkulu (njegegeyimu, ividiyo, noma izinhlelo zokusebenza zokuzula)\n • Landa noma layisha amafayela amakhulu\n • Sebenzisa ifoni yakho kumathempelesha aphezulu"</string>
+ <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Bona izinyathelo zokunakekelwa"</string>
<string name="high_temp_title" msgid="2218333576838496100">"Ifoni iyafudumala"</string>
- <string name="high_temp_notif_message" msgid="163928048626045592">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola"</string>
+ <string name="high_temp_notif_message" msgid="1277346543068257549">"Ezinye izici zikhawulelwe ngenkathi ifoni iphola.\nThepha mayelana nolwazi olwengeziwe"</string>
<string name="high_temp_dialog_message" msgid="3793606072661253968">"Ifoni yakho izozama ngokuzenzakalela ukuphola. Ungasasebenzisa ifoni yakho, kodwa ingasebenza ngokungasheshi.\n\nUma ifoni yakho isipholile, izosebenza ngokuvamile."</string>
+ <string name="high_temp_dialog_help_text" msgid="7380171287943345858">"Bona izinyathelo zokunakekelwa"</string>
<string name="high_temp_alarm_title" msgid="2359958549570161495">"Khipha ishaja"</string>
<string name="high_temp_alarm_notify_message" msgid="7186272817783835089">"Kukhona inkinga yokushaja le divayisi. Khipha i-adaptha yamandla, uphinde unakekele njengoba ikhebuli kungenzeka lifudumele."</string>
<string name="high_temp_alarm_help_care_steps" msgid="5017002218341329566">"Bona izinyathelo zokunakekelwa"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 3b6400f208bd..27db8cb5fb46 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -494,18 +494,6 @@
<!-- On debuggable builds, alert the user if SystemUI PSS goes over this number (in kb) -->
<integer name="watch_heap_limit">256000</integer>
- <!-- Animation duration for resizing of PIP when entering/exiting. -->
- <integer name="config_pipResizeAnimationDuration">425</integer>
-
- <!-- Allow dragging the PIP to a location to close it -->
- <bool name="config_pipEnableDismissDragToEdge">true</bool>
-
- <!-- Allow PIP to resize to a slightly bigger state upon touch/showing the menu -->
- <bool name="config_pipEnableResizeForMenu">true</bool>
-
- <!-- Allow PIP to enable round corner, see also R.dimen.pip_corner_radius -->
- <bool name="config_pipEnableRoundCorner">false</bool>
-
<!-- SystemUI Plugins that can be loaded on user builds. -->
<string-array name="config_pluginWhitelist" translatable="false">
<item>com.android.systemui</item>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
index ffd58dcfd50d..d8c9428f2676 100644
--- a/packages/SystemUI/res/values/config_tv.xml
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -22,4 +22,13 @@
<!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
when the PIP menu is shown in center. -->
<string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
+
+ <!-- Whether to enable microphone disclosure indicator
+ (com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar). -->
+ <bool name="audio_recording_disclosure_enabled">true</bool>
+
+ <!-- Whether the indicator should expand and show the recording application's label.
+ When disabled (false) the "minimized" indicator would appear on the screen whenever an
+ application is recording, but will not reveal to the user what application this is. -->
+ <bool name="audio_recording_disclosure_reveal_packages">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index eb3a55888e04..ea855eb722b9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -974,47 +974,8 @@
<!-- The start margin of quick scrub onboarding toast. -->
<dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
- <!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="floating_dismiss_gradient_height">250dp</dimen>
-
<dimen name="floating_dismiss_bottom_margin">50dp</dimen>
- <!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
- <dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
-
- <!-- The shortest-edge size of the expanded PiP. -->
- <dimen name="pip_expanded_shortest_edge_size">160dp</dimen>
-
- <!-- The additional offset to apply to the IME animation to account for the input field. -->
- <dimen name="pip_ime_offset">48dp</dimen>
-
- <!-- The padding between actions in the PiP in landscape Note that the PiP does not reflect
- the configuration of the device, so we can't use -land resources. -->
- <dimen name="pip_between_action_padding_land">8dp</dimen>
-
- <!-- The height of the PiP actions container in which the actions are vertically centered. -->
- <dimen name="pip_action_size">48dp</dimen>
-
- <!-- The padding around a PiP actions. -->
- <dimen name="pip_action_padding">12dp</dimen>
-
- <!-- The bottom margin of the expand container when there are actions.
- Equal to pip_action_size - pip_action_padding. -->
- <dimen name="pip_expand_container_edge_margin">30dp</dimen>
-
- <!-- The touchable/draggable edge size for PIP resize. -->
- <dimen name="pip_resize_edge_size">48dp</dimen>
-
- <!-- PIP Resize handle size and margin. -->
- <dimen name="pip_resize_handle_size">12dp</dimen>
- <dimen name="pip_resize_handle_margin">4dp</dimen>
-
- <!-- The corner radius for PiP window. -->
- <dimen name="pip_corner_radius">8dp</dimen>
-
- <!-- The buffer to use when calculating whether the pip is in an adjust zone. -->
- <dimen name="pip_bottom_offset_buffer">1dp</dimen>
-
<dimen name="default_gear_space">18dp</dimen>
<dimen name="cell_overlay_padding">18dp</dimen>
@@ -1249,7 +1210,6 @@
<dimen name="bubble_dismiss_target_padding_y">20dp</dimen>
<dimen name="bubble_manage_menu_elevation">4dp</dimen>
- <dimen name="dismiss_circle_size">52dp</dimen>
<dimen name="dismiss_target_x_size">24dp</dimen>
<!-- Bubbles user education views -->
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8212d6159737..a56f6f56836a 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -92,6 +92,8 @@
<item type="id" name="requires_remeasuring"/>
+ <item type="id" name="secondary_home_handle" />
+
<!-- Whether the icon is from a notification for which targetSdk < L -->
<item type="id" name="icon_is_pre_L"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 82c111f855e2..d97aea7dab59 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2374,45 +2374,6 @@
<!-- SysUI Tuner: Section to customize lockscreen shortcuts [CHAR LIMIT=60] -->
<string name="tuner_lock_screen">Lock screen</string>
- <!-- Making the PIP fullscreen [CHAR LIMIT=25] -->
- <string name="pip_phone_expand">Expand</string>
-
- <!-- Label for PIP action to Minimize the PIP [CHAR LIMIT=25] -->
- <string name="pip_phone_minimize">Minimize</string>
-
- <!-- Label for PIP close button [CHAR LIMIT=NONE]-->
- <string name="pip_phone_close">Close</string>
-
- <!-- Label for PIP settings button [CHAR LIMIT=NONE]-->
- <string name="pip_phone_settings">Settings</string>
-
- <!-- Label for PIP the drag to dismiss hint [CHAR LIMIT=NONE]-->
- <string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
-
- <!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
- <string name="pip_menu_title">Menu</string>
-
- <!-- PiP BTW notification title. [CHAR LIMIT=50] -->
- <string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
-
- <!-- PiP BTW notification description. [CHAR LIMIT=NONE] -->
- <string name="pip_notification_message">If you don\'t want <xliff:g id="name" example="Google Maps">%s</xliff:g> to use this feature, tap to open settings and turn it off.</string>
-
- <!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
- <string name="pip_play">Play</string>
-
- <!-- Button to pause the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
- <string name="pip_pause">Pause</string>
-
- <!-- Button to skip to the next media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
- <string name="pip_skip_to_next">Skip to next</string>
-
- <!-- Button to skip to the prev media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
- <string name="pip_skip_to_prev">Skip to previous</string>
-
- <!-- Accessibility action for resizing PIP [CHAR LIMIT=NONE] -->
- <string name="accessibility_action_pip_resize">Resize</string>
-
<!-- Tuner string -->
<string name="change_theme_reboot" translatable="false">Changing the theme requires a restart.</string>
<!-- Tuner string -->
@@ -2422,17 +2383,26 @@
<!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=40] -->
<string name="thermal_shutdown_title">Phone turned off due to heat</string>
- <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=100] -->
- <string name="thermal_shutdown_message">Your phone is now running normally</string>
- <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=450] -->
+ <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=120] -->
+ <string name="thermal_shutdown_message">Your phone is now running normally.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone last shut down because it got too hot. [CHAR LIMIT=500] -->
<string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t&#8226; Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t&#8226; Download or upload large files\n\t&#8226; Use your phone in high temperatures</string>
+ <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
+ <string name="thermal_shutdown_dialog_help_text">See care steps</string>
+ <!-- URL for care instructions for overheating devices -->
+ <string name="thermal_shutdown_dialog_help_url" translatable="false"></string>
<!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
<string name="high_temp_title">Phone is getting warm</string>
- <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=100] -->
- <string name="high_temp_notif_message">Some features limited while phone cools down</string>
- <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
+ <!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=120] -->
+ <string name="high_temp_notif_message">Some features limited while phone cools down.\nTap for more info</string>
+ <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=350] -->
<string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+ <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
+ <string name="high_temp_dialog_help_text">See care steps</string>
+ <!-- URL for care instructions for overheating devices -->
+ <string name="high_temp_dialog_help_url" translatable="false"></string>
+
<!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
<string name="high_temp_alarm_title">Unplug charger</string>
<!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 6d61ff989cb1..5d7f08eef0a1 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -17,21 +17,6 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Picture-in-Picture (PIP) notification -->
- <!-- Title for the notification channel for TV PIP controls. [CHAR LIMIT=NONE] -->
- <string name="notification_channel_tv_pip">Picture-in-Picture</string>
- <!-- Title of the picture-in-picture (PIP) notification title
- when the media doesn't have title [CHAR LIMIT=NONE] -->
- <string name="pip_notification_unknown_title">(No title program)</string>
-
- <!-- Picture-in-Picture (PIP) menu -->
- <eat-comment />
- <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
- <string name="pip_close">Close PIP</string>
- <!-- Button to move picture-in-picture (PIP) screen to the fullscreen in PIP menu [CHAR LIMIT=30] -->
- <string name="pip_fullscreen">Full screen</string>
-
<!-- Title and subtitle for AudioRecordingIndicator -->
<string name="mic_active">Microphone Active</string>
<string name="app_accessed_mic">%1$s accessed your microphone</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 71969e06ece1..498b6b2455d7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -55,6 +55,7 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -1073,6 +1074,15 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
}
+ private boolean isEncryptedOrLockdown(int userId) {
+ final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(userId);
+ final boolean isLockDown =
+ containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+ || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ final boolean isEncrypted = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT);
+ return isEncrypted || isLockDown;
+ }
+
public boolean userNeedsStrongAuth() {
return mStrongAuthTracker.getStrongAuthForUser(getCurrentUser())
!= LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
@@ -1249,7 +1259,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
- private FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
+ private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback
+ = (sensorId, userId, isStrongBiometric) -> {
+ // Trigger the fingerprint success path so the bouncer can be shown
+ handleFingerprintAuthenticated(userId, isStrongBiometric);
+ };
+
+ private final FingerprintManager.AuthenticationCallback mFingerprintAuthenticationCallback
= new AuthenticationCallback() {
@Override
@@ -1280,6 +1296,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
};
+ private final FaceManager.FaceDetectionCallback mFaceDetectionCallback
+ = (sensorId, userId, isStrongBiometric) -> {
+ // Trigger the face success path so the bouncer can be shown
+ handleFaceAuthenticated(userId, isStrongBiometric);
+ };
+
@VisibleForTesting
FaceManager.AuthenticationCallback mFaceAuthenticationCallback
= new FaceManager.AuthenticationCallback() {
@@ -1316,6 +1338,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private CancellationSignal mFaceCancelSignal;
private FingerprintManager mFpm;
private FaceManager mFaceManager;
+ private FaceSensorProperties mFaceSensorProperties;
private boolean mFingerprintLockedOut;
private TelephonyManager mTelephonyManager;
@@ -1757,6 +1780,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
mFaceManager = (FaceManager) context.getSystemService(Context.FACE_SERVICE);
+ mFaceSensorProperties = mFaceManager.getSensorProperties();
}
if (mFpm != null || mFaceManager != null) {
@@ -2051,8 +2075,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFingerprintCancelSignal.cancel();
}
mFingerprintCancelSignal = new CancellationSignal();
- mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
- mFingerprintAuthenticationCallback, null /* handler */, userId);
+
+ if (isEncryptedOrLockdown(userId)) {
+ mFpm.detectFingerprint(mFingerprintCancelSignal, mFingerprintDetectionCallback,
+ userId, null /* surface */);
+ } else {
+ mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
+ mFingerprintAuthenticationCallback, null /* handler */, userId);
+ }
setFingerprintRunningState(BIOMETRIC_STATE_RUNNING);
}
}
@@ -2069,8 +2099,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mFaceCancelSignal.cancel();
}
mFaceCancelSignal = new CancellationSignal();
- mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
- mFaceAuthenticationCallback, null /* handler */, userId);
+
+ if (isEncryptedOrLockdown(userId) && mFaceSensorProperties.supportsFaceDetection) {
+ mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
+ } else {
+ mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
+ mFaceAuthenticationCallback, null /* handler */, userId);
+ }
setFaceRunningState(BIOMETRIC_STATE_RUNNING);
}
}
@@ -2088,7 +2123,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean isUnlockWithFingerprintPossible(int userId) {
return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
- && mFpm.getEnrolledFingerprints(userId).size() > 0;
+ && mFpm.hasEnrolledTemplates(userId);
}
private boolean isUnlockWithFacePossible(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index a46ab3a9e35b..58698151b655 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -15,8 +15,6 @@
*/
package com.android.systemui;
-import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
-import static android.app.StatusBarManager.DISABLE_NONE;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -56,7 +54,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.settings.CurrentUserTracker;
-import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -64,7 +61,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils.DisableStateTracker;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -137,11 +133,6 @@ public class BatteryMeterView extends LinearLayout implements
mShowPercentAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_battery_percentage_setting_available);
-
- addOnAttachStateChangeListener(
- new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS,
- Dependency.get(CommandQueue.class)));
-
setupLayoutTransition();
mSlotBattery = context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 332a00d1d4e7..398a2c9c9d41 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.PixelFormat;
import android.provider.Settings;
@@ -23,6 +24,7 @@ import android.view.Gravity;
import android.view.WindowManager;
import android.widget.ImageView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
/**
@@ -42,23 +44,36 @@ class MagnificationModeSwitch {
private boolean mIsVisible = false;
MagnificationModeSwitch(Context context) {
+ this(context, createView(context));
+ }
+
+ @VisibleForTesting
+ MagnificationModeSwitch(Context context, @NonNull ImageView imageView) {
mContext = context;
mWindowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
mParams = createLayoutParams();
- mImageView = createView(mContext, mMagnificationMode);
+ mImageView = imageView;
+ applyResourcesValues();
mImageView.setOnClickListener(
view -> {
removeButton();
toggleMagnificationMode();
});
+ mImageView.setImageResource(getIconResId(mMagnificationMode));
+ }
+
+ private void applyResourcesValues() {
+ final int padding = mContext.getResources().getDimensionPixelSize(
+ R.dimen.magnification_switch_button_padding);
+ mImageView.setPadding(padding, padding, padding, padding);
}
void removeButton() {
- mImageView.animate().cancel();
if (!mIsVisible) {
return;
}
+ mImageView.animate().cancel();
mWindowManager.removeView(mImageView);
mIsVisible = false;
}
@@ -72,7 +87,7 @@ class MagnificationModeSwitch {
mWindowManager.addView(mImageView, mParams);
mIsVisible = true;
}
-
+ mImageView.setAlpha(1.0f);
// TODO(b/143852371): use accessibility timeout as a delay.
// Dismiss the magnification switch button after the button is displayed for a period of
// time.
@@ -82,30 +97,29 @@ class MagnificationModeSwitch {
.setStartDelay(START_DELAY_MS)
.setDuration(DURATION_MS)
.withEndAction(
- () -> removeButton());
+ () -> removeButton())
+ .start();
}
private void toggleMagnificationMode() {
final int newMode =
mMagnificationMode ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
mMagnificationMode = newMode;
+ mImageView.setImageResource(getIconResId(newMode));
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, newMode);
}
- private static ImageView createView(Context context, int mode) {
- final int padding = context.getResources().getDimensionPixelSize(
- R.dimen.magnification_switch_button_padding);
+ private static ImageView createView(Context context) {
ImageView imageView = new ImageView(context);
- imageView.setImageResource(getIconResId(mode));
imageView.setClickable(true);
imageView.setFocusable(true);
- imageView.setPadding(padding, padding, padding, padding);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
return imageView;
}
- private static int getIconResId(int mode) {
+ @VisibleForTesting
+ static int getIconResId(int mode) {
return (mode == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)
? R.drawable.ic_open_in_new_window
: R.drawable.ic_open_in_new_fullscreen;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 7e9faff8c296..8b6581ff1856 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -258,8 +258,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
- params.x = mMagnificationFrame.left;
- params.y = mMagnificationFrame.top;
+ params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
+ params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
params.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
params.setTitle(mContext.getString(R.string.magnification_window_title));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 7b441d64af06..42911374dc87 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -246,11 +246,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
IActivityTaskManager getActivityTaskManager() {
return ActivityTaskManager.getService();
}
-
- IFingerprintService getFingerprintService() {
- return IFingerprintService.Stub.asInterface(
- ServiceManager.getService(Context.FINGERPRINT_SERVICE));
- }
}
@Inject
@@ -276,23 +271,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
mActivityTaskManager = mInjector.getActivityTaskManager();
- if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- IFingerprintService fingerprintService = mInjector.getFingerprintService();
- if (fingerprintService == null) {
- Log.e(TAG, "FEATURE_FINGERPRINT is available, but FingerprintService is null");
- } else {
- boolean isUdfps = false;
- try {
- // TODO(b/160024833): Enumerate through all of the sensors and check whether
- // at least one of them is UDFPS.
- isUdfps = fingerprintService.isUdfps(0 /* sensorId */);
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to check whether the sensor is a UDFPS", e);
- }
- if (isUdfps) {
- mUdfpsController = new UdfpsController(mContext, fingerprintService,
- mWindowManager);
- }
+ final FingerprintManager fpm = mContext.getSystemService(FingerprintManager.class);
+ if (fpm != null && fpm.isHardwareDetected()) {
+ // TODO(b/160024833): Enumerate through all of the sensors and check whether
+ // at least one of them is UDFPS.
+ if (fpm.isUdfps()) {
+ mUdfpsController = new UdfpsController(mContext, mWindowManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 97e97ffaae0c..739c2b155444 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintService;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
@@ -44,7 +45,7 @@ class UdfpsController {
private static final String TAG = "UdfpsController";
private final Context mContext;
- private final IFingerprintService mFingerprintService;
+ private final FingerprintManager mFingerprintManager;
private final WindowManager mWindowManager;
private final Handler mHandler;
@@ -94,10 +95,9 @@ class UdfpsController {
}
};
- UdfpsController(Context context, IFingerprintService fingerprintService,
- WindowManager windowManager) {
+ UdfpsController(Context context, WindowManager windowManager) {
mContext = context;
- mFingerprintService = fingerprintService;
+ mFingerprintManager = context.getSystemService(FingerprintManager.class);
mWindowManager = windowManager;
mHandler = new Handler(Looper.getMainLooper());
start();
@@ -133,11 +133,7 @@ class UdfpsController {
mHbmEnableCommand = mContext.getResources().getString(R.string.udfps_hbm_enable_command);
mHbmDisableCommand = mContext.getResources().getString(R.string.udfps_hbm_disable_command);
- try {
- mFingerprintService.setUdfpsOverlayController(new UdfpsOverlayController());
- } catch (RemoteException e) {
- Log.e(TAG, "start | failed to set UDFPS controller", e);
- }
+ mFingerprintManager.setUdfpsOverlayController(new UdfpsOverlayController());
mIsOverlayShowing = false;
}
@@ -156,6 +152,7 @@ class UdfpsController {
}
private void hideUdfpsOverlay() {
+ onFingerUp();
mHandler.post(() -> {
Log.v(TAG, "hideUdfpsOverlay | removing window");
if (mIsOverlayShowing) {
@@ -174,19 +171,11 @@ class UdfpsController {
Log.e(TAG, "onFingerDown | failed to enable HBM: " + e.getMessage());
}
mView.onFingerDown();
- try {
- mFingerprintService.onFingerDown(x, y, minor, major);
- } catch (RemoteException e) {
- Log.e(TAG, "onFingerDown | failed to propagate onFingerDown", e);
- }
+ mFingerprintManager.onFingerDown(x, y, minor, major);
}
private void onFingerUp() {
- try {
- mFingerprintService.onFingerUp();
- } catch (RemoteException e) {
- Log.e(TAG, "onFingeUp | failed to propagate onFingerUp", e);
- }
+ mFingerprintManager.onFingerUp();
mView.onFingerUp();
try {
FileWriter fw = new FileWriter(mHbmPath);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index dfc7d53f08a7..8190550a74fc 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -143,12 +143,12 @@ public class UdfpsView extends View {
void onFingerDown() {
mIsFingerDown = true;
mSensorPaint.setStyle(Paint.Style.FILL);
- invalidate();
+ postInvalidate();
}
void onFingerUp() {
mIsFingerDown = false;
mSensorPaint.setStyle(Paint.Style.STROKE);
- invalidate();
+ postInvalidate();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 1354585ea396..434bf49ac878 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -207,12 +207,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
/** Whether or not the BubbleStackView has been added to the WindowManager. */
private boolean mAddedToWindowManager = false;
- /**
- * Value from {@link NotificationShadeWindowController#getForceHasTopUi()} when we forced top UI
- * due to expansion. We'll restore this value when the stack collapses.
- */
- private boolean mHadTopUi = false;
-
// Listens to user switch so bubbles can be saved and restored.
private final NotificationLockscreenUserManager mNotifUserManager;
@@ -1304,7 +1298,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// Collapsing? Do this first before remaining steps.
if (update.expandedChanged && !update.expanded) {
mStackView.setExpanded(false);
- mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
}
// Do removals, if any.
@@ -1394,8 +1388,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (update.expandedChanged && update.expanded) {
if (mStackView != null) {
mStackView.setExpanded(true);
- mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
- mNotificationShadeWindowController.setForceHasTopUi(true);
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
index 57e2362bd511..d017bc0e31c2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java
@@ -24,6 +24,8 @@ import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
@@ -40,15 +42,15 @@ import com.android.systemui.R;
*/
public class BubbleIconFactory extends BaseIconFactory {
+ private int mBadgeSize;
+
protected BubbleIconFactory(Context context) {
super(context, context.getResources().getConfiguration().densityDpi,
context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size));
- }
-
- int getBadgeSize() {
- return mContext.getResources().getDimensionPixelSize(
+ mBadgeSize = mContext.getResources().getDimensionPixelSize(
com.android.launcher3.icons.R.dimen.profile_badge_size);
}
+
/**
* Returns the drawable that the developer has provided to display in the bubble.
*/
@@ -78,18 +80,20 @@ public class BubbleIconFactory extends BaseIconFactory {
* will include the workprofile indicator on the badge if appropriate.
*/
BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) {
- Bitmap userBadgedBitmap = createIconBitmap(
- userBadgedAppIcon, 1f, getBadgeSize());
- ShadowGenerator shadowGenerator = new ShadowGenerator(getBadgeSize());
- if (!isImportantConversation) {
- Canvas c = new Canvas();
- c.setBitmap(userBadgedBitmap);
- shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
- return createIconBitmap(userBadgedBitmap);
- } else {
- float ringStrokeWidth = mContext.getResources().getDimensionPixelSize(
+ ShadowGenerator shadowGenerator = new ShadowGenerator(mBadgeSize);
+ Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mBadgeSize);
+
+ if (userBadgedAppIcon instanceof AdaptiveIconDrawable) {
+ userBadgedBitmap = Bitmap.createScaledBitmap(
+ getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */
+ userBadgedAppIcon.getIntrinsicWidth()),
+ mBadgeSize, mBadgeSize, /* filter */ true);
+ }
+
+ if (isImportantConversation) {
+ final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width);
- int importantConversationColor = mContext.getResources().getColor(
+ final int importantConversationColor = mContext.getResources().getColor(
com.android.settingslib.R.color.important_conversation, null);
Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(),
userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig());
@@ -114,9 +118,45 @@ public class BubbleIconFactory extends BaseIconFactory {
shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c);
return createIconBitmap(badgeAndRing);
+ } else {
+ Canvas c = new Canvas();
+ c.setBitmap(userBadgedBitmap);
+ shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c);
+ return createIconBitmap(userBadgedBitmap);
}
}
+ public Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) {
+ Drawable foreground = icon.getForeground();
+ Drawable background = icon.getBackground();
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas();
+ canvas.setBitmap(bitmap);
+
+ // Clip canvas to circle.
+ Path circlePath = new Path();
+ circlePath.addCircle(/* x */ size / 2f,
+ /* y */ size / 2f,
+ /* radius */ size / 2f,
+ Path.Direction.CW);
+ canvas.clipPath(circlePath);
+
+ // Draw background.
+ background.setBounds(0, 0, size, size);
+ background.draw(canvas);
+
+ // Draw foreground. The foreground and background drawables are derived from adaptive icons
+ // Some icon shapes fill more space than others, so adaptive icons are normalized to about
+ // the same size. This size is smaller than the original bounds, so we estimate
+ // the difference in this offset.
+ int offset = size / 5;
+ foreground.setBounds(-offset, -offset, size + offset, size + offset);
+ foreground.draw(canvas);
+
+ canvas.setBitmap(null);
+ return bitmap;
+ }
+
/**
* Returns a {@link BitmapInfo} for the entire bubble icon including the badge.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b2e91643bed2..ef51abb1404d 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -2129,7 +2129,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private boolean mShowing;
private float mScrimAlpha;
private ResetOrientationData mResetOrientationData;
- private boolean mHadTopUi;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
@@ -2397,8 +2396,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
public void show() {
super.show();
mShowing = true;
- mHadTopUi = mNotificationShadeWindowController.getForceHasTopUi();
- mNotificationShadeWindowController.setForceHasTopUi(true);
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
.commitUpdate(mContext.getDisplayId());
@@ -2499,7 +2497,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
dismissOverflow(true);
dismissPowerOptions(true);
if (mControlsUiController != null) mControlsUiController.hide();
- mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
mDepthController.updateGlobalDialogVisibility(0, null /* view */);
mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
.commitUpdate(mContext.getDisplayId());
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 78d70877a90e..e8dba8f3b585 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -217,10 +217,10 @@ class LogBuffer(
private fun dumpMessage(message: LogMessage, pw: PrintWriter) {
pw.print(DATE_FORMAT.format(message.timestamp))
pw.print(" ")
- pw.print(message.level)
+ pw.print(message.level.shortString)
pw.print(" ")
pw.print(message.tag)
- pw.print(" ")
+ pw.print(": ")
pw.println(message.printer(message))
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt b/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt
index 7b9af0f91200..53f231c9f9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogLevel.kt
@@ -21,11 +21,14 @@ import android.util.Log
/**
* Enum version of @Log.Level
*/
-enum class LogLevel(@Log.Level val nativeLevel: Int) {
- VERBOSE(Log.VERBOSE),
- DEBUG(Log.DEBUG),
- INFO(Log.INFO),
- WARNING(Log.WARN),
- ERROR(Log.ERROR),
- WTF(Log.ASSERT)
+enum class LogLevel(
+ @Log.Level val nativeLevel: Int,
+ val shortString: String
+) {
+ VERBOSE(Log.VERBOSE, "V"),
+ DEBUG(Log.DEBUG, "D"),
+ INFO(Log.INFO, "I"),
+ WARNING(Log.WARN, "W"),
+ ERROR(Log.ERROR, "E"),
+ WTF(Log.ASSERT, "WTF")
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index ead17867844a..72019315139b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -21,7 +21,6 @@ import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
-import android.content.Context;
import android.graphics.Rect;
import android.view.SurfaceControl;
@@ -56,13 +55,15 @@ public class PipAnimationController {
public static final int TRANSITION_DIRECTION_TO_PIP = 2;
public static final int TRANSITION_DIRECTION_TO_FULLSCREEN = 3;
public static final int TRANSITION_DIRECTION_TO_SPLIT_SCREEN = 4;
+ public static final int TRANSITION_DIRECTION_REMOVE_STACK = 5;
@IntDef(prefix = { "TRANSITION_DIRECTION_" }, value = {
TRANSITION_DIRECTION_NONE,
TRANSITION_DIRECTION_SAME,
TRANSITION_DIRECTION_TO_PIP,
TRANSITION_DIRECTION_TO_FULLSCREEN,
- TRANSITION_DIRECTION_TO_SPLIT_SCREEN
+ TRANSITION_DIRECTION_TO_SPLIT_SCREEN,
+ TRANSITION_DIRECTION_REMOVE_STACK
})
@Retention(RetentionPolicy.SOURCE)
public @interface TransitionDirection {}
@@ -88,7 +89,7 @@ public class PipAnimationController {
});
@Inject
- PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
+ PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
}
@@ -338,6 +339,10 @@ public class PipAnimationController {
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
+ if (getTransitionDirection() == TRANSITION_DIRECTION_REMOVE_STACK) {
+ // while removing the pip stack, no extra work needs to be done here.
+ return;
+ }
getSurfaceTransactionHelper()
.resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds())
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 8bbd15babf19..665b90e29976 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -34,6 +34,7 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.util.TypedValue;
+import android.view.Display;
import android.view.DisplayInfo;
import android.view.Gravity;
import android.window.WindowContainerTransaction;
@@ -60,7 +61,7 @@ public class PipBoundsHandler {
private final PipSnapAlgorithm mSnapAlgorithm;
private final DisplayInfo mDisplayInfo = new DisplayInfo();
private final DisplayController mDisplayController;
- private final DisplayLayout mDisplayLayout;
+ private DisplayLayout mDisplayLayout;
private ComponentName mLastPipComponentName;
private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
@@ -177,7 +178,7 @@ public class PipBoundsHandler {
}
if (isValidPictureInPictureAspectRatio(mAspectRatio)) {
transformBoundsToAspectRatio(normalBounds, mAspectRatio,
- false /* useCurrentMinEdgeSize */);
+ false /* useCurrentMinEdgeSize */, false /* useCurrentSize */);
}
displayInfo.copyFrom(mDisplayInfo);
}
@@ -278,7 +279,9 @@ public class PipBoundsHandler {
destinationBounds = new Rect(bounds);
}
if (isValidPictureInPictureAspectRatio(aspectRatio)) {
- transformBoundsToAspectRatio(destinationBounds, aspectRatio, useCurrentMinEdgeSize);
+ boolean useCurrentSize = bounds == null && mReentrySize != null;
+ transformBoundsToAspectRatio(destinationBounds, aspectRatio, useCurrentMinEdgeSize,
+ useCurrentSize);
}
mAspectRatio = aspectRatio;
return destinationBounds;
@@ -288,6 +291,10 @@ public class PipBoundsHandler {
return mDefaultAspectRatio;
}
+ public void onOverlayChanged(Context context, Display display) {
+ mDisplayLayout = new DisplayLayout(context, display);
+ }
+
/**
* Updatest the display info and display layout on rotation change. This is needed even when we
* aren't in PIP because the rotation layout is used to calculate the proper insets for the
@@ -384,7 +391,8 @@ public class PipBoundsHandler {
* @param stackBounds
*/
public void transformBoundsToAspectRatio(Rect stackBounds) {
- transformBoundsToAspectRatio(stackBounds, mAspectRatio, true);
+ transformBoundsToAspectRatio(stackBounds, mAspectRatio, true /* useCurrentMinEdgeSize */,
+ true /* useCurrentSize */);
}
/**
@@ -392,18 +400,16 @@ public class PipBoundsHandler {
* specified aspect ratio.
*/
private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
- boolean useCurrentMinEdgeSize) {
+ boolean useCurrentMinEdgeSize, boolean useCurrentSize) {
// Save the snap fraction and adjust the size based on the new aspect ratio.
final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
getMovementBounds(stackBounds));
- final int minEdgeSize;
+ final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
final Size size;
- if (useCurrentMinEdgeSize) {
- minEdgeSize = mCurrentMinSize;
+ if (useCurrentMinEdgeSize || useCurrentSize) {
size = mSnapAlgorithm.getSizeForAspectRatio(
new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
} else {
- minEdgeSize = mDefaultMinSize;
size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index 65ea887259be..2c7ec48e4ae7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -23,8 +23,8 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.view.SurfaceControl;
-import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.wm.shell.R;
import javax.inject.Inject;
import javax.inject.Singleton;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 0141dee04086..0d6b522046f7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -24,6 +24,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
+import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
@@ -55,10 +56,10 @@ import android.window.WindowContainerTransactionCallback;
import android.window.WindowOrganizer;
import com.android.internal.os.SomeArgs;
-import com.android.systemui.R;
import com.android.systemui.pip.phone.PipUpdateThread;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.wm.DisplayController;
+import com.android.wm.shell.R;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -337,23 +338,32 @@ public class PipTaskOrganizer extends TaskOrganizer implements
+ " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken);
return;
}
- getUpdateHandler().post(() -> {
- try {
- // Reset the task bounds first to ensure the activity configuration is reset as well
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setBounds(mToken, null);
- WindowOrganizer.applyTransaction(wct);
-
- ActivityTaskManager.getService().removeStacksInWindowingModes(
- new int[]{ WINDOWING_MODE_PINNED });
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to remove PiP", e);
- }
- });
+
+ // removePipImmediately is expected when the following animation finishes.
+ mUpdateHandler.post(() -> mPipAnimationController
+ .getAnimator(mLeash, mLastReportedBounds, 1f, 0f)
+ .setTransitionDirection(TRANSITION_DIRECTION_REMOVE_STACK)
+ .setPipAnimationCallback(mPipAnimationCallback)
+ .setDuration(mEnterExitAnimationDuration)
+ .start());
mInitialState.remove(mToken.asBinder());
mExitingPip = true;
}
+ private void removePipImmediately() {
+ try {
+ // Reset the task bounds first to ensure the activity configuration is reset as well
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.setBounds(mToken, null);
+ WindowOrganizer.applyTransaction(wct);
+
+ ActivityTaskManager.getService().removeStacksInWindowingModes(
+ new int[]{ WINDOWING_MODE_PINNED });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove PiP", e);
+ }
+ }
+
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {
Objects.requireNonNull(info, "Requires RunningTaskInfo");
@@ -803,7 +813,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements
+ "directly");
}
mLastReportedBounds.set(destinationBounds);
- if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
+ if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
+ removePipImmediately();
+ return;
+ } else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
index 8b3f4cb196bf..c715398d52da 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAccessibilityInteractionConnection.java
@@ -27,9 +27,9 @@ import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
-import com.android.systemui.R;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 2802702aa0b4..02bf475d5744 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -53,10 +53,12 @@ import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.wm.DisplayChangeController;
import com.android.systemui.wm.DisplayController;
+import com.android.systemui.wm.DisplayLayout;
import java.io.PrintWriter;
@@ -234,6 +236,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
}
+ public ConfigurationController.ConfigurationListener mOverlayChangedListener =
+ new ConfigurationController.ConfigurationListener() {
+ @Override
+ public void onOverlayChanged() {
+ mHandler.post(() -> {
+ mPipBoundsHandler.onOverlayChanged(mContext, mContext.getDisplay());
+ updateMovementBounds(null /* toBounds */,
+ false /* fromRotation */, false /* fromImeAdjustment */,
+ false /* fromShelfAdjustment */, null /* windowContainerTransaction */);
+ });
+ }
+ };
+
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
DisplayController displayController,
@@ -242,7 +257,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
PipBoundsHandler pipBoundsHandler,
PipSnapAlgorithm pipSnapAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
- SysUiState sysUiState) {
+ SysUiState sysUiState,
+ ConfigurationController configController) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -275,6 +291,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
context.getDisplay().getDisplayInfo(displayInfo);
mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
+ configController.addCallback(mOverlayChangedListener);
+
try {
mPipTaskOrganizer.registerOrganizer(WINDOWING_MODE_PINNED);
ActivityManager.StackInfo stackInfo = ActivityTaskManager.getService().getStackInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index 849a62add80f..05b9b0ec3957 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -36,9 +36,9 @@ import android.media.session.PlaybackState;
import android.os.UserHandle;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.Collections;
@@ -194,13 +194,13 @@ public class PipMediaController {
private void createMediaActions() {
String pauseDescription = mContext.getString(R.string.pip_pause);
mPauseAction = new RemoteAction(Icon.createWithResource(mContext,
- R.drawable.ic_pause_white), pauseDescription, pauseDescription,
+ R.drawable.pip_ic_pause_white), pauseDescription, pauseDescription,
PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
FLAG_UPDATE_CURRENT));
String playDescription = mContext.getString(R.string.pip_play);
mPlayAction = new RemoteAction(Icon.createWithResource(mContext,
- R.drawable.ic_play_arrow_white), playDescription, playDescription,
+ R.drawable.pip_ic_play_arrow_white), playDescription, playDescription,
PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
FLAG_UPDATE_CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 89df3722bbeb..ad5a13e78cb4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -76,7 +76,7 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import com.android.systemui.Interpolators;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 8a2e4ae11878..9f0b1de21b52 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -26,9 +26,10 @@ import android.os.Debug;
import android.util.Log;
import android.view.Choreographer;
+import androidx.dynamicanimation.animation.AnimationHandler;
+import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -74,9 +75,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** The region that all of PIP must stay within. */
private final Rect mFloatingAllowedArea = new Rect();
- private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
- new SfVsyncFrameCallbackProvider();
-
/**
* Temporary bounds used when PIP is being dragged or animated. These bounds are applied to PIP
* using {@link PipTaskOrganizer#scheduleUserResizePip}, so that we can animate shrinking into
@@ -94,8 +92,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** Coordinator instance for resolving conflicts with other floating content. */
private FloatingContentCoordinator mFloatingContentCoordinator;
- /** Callback that re-sizes PIP to the animated bounds. */
- private final Choreographer.FrameCallback mResizePipVsyncCallback;
+ private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+ ThreadLocal.withInitial(() -> {
+ FrameCallbackScheduler scheduler = runnable ->
+ Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
+ AnimationHandler handler = new AnimationHandler(scheduler);
+ return handler;
+ });
/**
* PhysicsAnimator instance for animating {@link #mTemporaryBounds} using physics animations.
@@ -171,16 +174,15 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
+ mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
+ mSfAnimationHandlerThreadLocal.get());
- mResizePipVsyncCallback = l -> {
+ mResizePipUpdateListener = (target, values) -> {
if (!mTemporaryBounds.isEmpty()) {
mPipTaskOrganizer.scheduleUserResizePip(
mBounds, mTemporaryBounds, null);
}
};
-
- mResizePipUpdateListener = (target, values) ->
- mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
}
@NonNull
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 1ca53f907994..d884fa956edc 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -49,16 +49,15 @@ import android.view.MotionEvent;
import android.view.ViewConfiguration;
import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.util.DeviceConfigProxy;
+import com.android.wm.shell.R;
import java.io.PrintWriter;
import java.util.concurrent.Executor;
import java.util.function.Function;
-import java.util.function.Supplier;
/**
* Helper on top of PipTouchHandler that handles inputs OUTSIDE of the PIP window, which is used to
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 32f8c126373d..f4553fd3d716 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -56,7 +56,6 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
-import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
@@ -68,6 +67,7 @@ import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
import com.android.systemui.util.magnetictarget.MagnetizedObject;
+import com.android.wm.shell.R;
import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
index b21cd95626a7..db9bedd2e620 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlButtonView.java
@@ -28,7 +28,7 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
* A view containing PIP controls including fullscreen, close, and media controls.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
index 8efeef1ffa0a..125444d2dfb5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java
@@ -22,7 +22,7 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
-import com.android.systemui.R;
+import com.android.wm.shell.R;
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
index bb588d409dc8..05bb882ea52e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java
@@ -26,8 +26,8 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
@@ -216,10 +216,10 @@ public class PipControlsViewController {
} else {
mPlayPauseButtonView.setVisibility(View.VISIBLE);
if (state == PipManager.PLAYBACK_STATE_PLAYING) {
- mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white);
+ mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white);
mPlayPauseButtonView.setText(R.string.pip_pause);
} else {
- mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white);
+ mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_play_arrow_white);
mPlayPauseButtonView.setText(R.string.pip_play);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index bf82a3f953d1..b8947ab05968 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -47,7 +47,6 @@ import android.util.Pair;
import android.view.DisplayInfo;
import com.android.systemui.Dependency;
-import com.android.systemui.R;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.pip.BasePipManager;
@@ -59,6 +58,7 @@ import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedSta
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.stackdivider.Divider;
+import com.android.wm.shell.R;
import java.util.ArrayList;
import java.util.List;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
index c2b9af326650..214088c99eeb 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java
@@ -25,8 +25,8 @@ import android.content.pm.ParceledListSlice;
import android.os.Bundle;
import android.util.Log;
-import com.android.systemui.R;
import com.android.systemui.pip.tv.dagger.TvPipComponent;
+import com.android.wm.shell.R;
import java.util.Collections;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5b549cd92b18..651a4f367f21 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -36,9 +36,9 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.util.NotificationChannels;
+import com.android.wm.shell.R;
/**
* A notification that informs users that PIP is running and also provides PIP controls.
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 10b04c0129e4..6abbbbeaa397 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -24,6 +24,7 @@ import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioAttributes;
@@ -376,13 +377,15 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
return;
}
mHighTempWarning = true;
+ final String message = mContext.getString(R.string.high_temp_notif_message);
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.ic_device_thermostat_24)
.setWhen(0)
.setShowWhen(false)
.setContentTitle(mContext.getString(R.string.high_temp_title))
- .setContentText(mContext.getString(R.string.high_temp_notif_message))
+ .setContentText(message)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingBroadcast(ACTION_CLICKED_TEMP_WARNING))
.setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_TEMP_WARNING))
@@ -402,6 +405,23 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
d.setPositiveButton(com.android.internal.R.string.ok, null);
d.setShowForAllUsers(true);
d.setOnDismissListener(dialog -> mHighTempDialog = null);
+ final String url = mContext.getString(R.string.high_temp_dialog_help_url);
+ if (!url.isEmpty()) {
+ d.setNeutralButton(R.string.high_temp_dialog_help_text,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Intent helpIntent =
+ new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(url))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+ true /* dismissShade */, resultCode -> {
+ mHighTempDialog = null;
+ });
+ }
+ });
+ }
d.show();
mHighTempDialog = d;
}
@@ -420,19 +440,38 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
d.setPositiveButton(com.android.internal.R.string.ok, null);
d.setShowForAllUsers(true);
d.setOnDismissListener(dialog -> mThermalShutdownDialog = null);
+ final String url = mContext.getString(R.string.thermal_shutdown_dialog_help_url);
+ if (!url.isEmpty()) {
+ d.setNeutralButton(R.string.thermal_shutdown_dialog_help_text,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final Intent helpIntent =
+ new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(url))
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+ true /* dismissShade */, resultCode -> {
+ mThermalShutdownDialog = null;
+ });
+ }
+ });
+ }
d.show();
mThermalShutdownDialog = d;
}
@Override
public void showThermalShutdownWarning() {
+ final String message = mContext.getString(R.string.thermal_shutdown_message);
final Notification.Builder nb =
new Notification.Builder(mContext, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.ic_device_thermostat_24)
.setWhen(0)
.setShowWhen(false)
.setContentTitle(mContext.getString(R.string.thermal_shutdown_title))
- .setContentText(mContext.getString(R.string.thermal_shutdown_message))
+ .setContentText(message)
+ .setStyle(new Notification.BigTextStyle().bigText(message))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setContentIntent(pendingBroadcast(ACTION_CLICKED_THERMAL_SHUTDOWN_WARNING))
.setDeleteIntent(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index c4bb4e86e41e..6e4ab9a3323a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -78,6 +78,8 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
private SettingsButton mSettingsButton;
protected View mSettingsContainer;
private PageIndicator mPageIndicator;
+ private TextView mBuildText;
+ private boolean mShouldShowBuildText;
private boolean mQsDisabled;
private QSPanel mQsPanel;
@@ -147,6 +149,7 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mActionsContainer = findViewById(R.id.qs_footer_actions_container);
mEditContainer = findViewById(R.id.qs_footer_actions_edit_container);
+ mBuildText = findViewById(R.id.build);
// RenderThread is doing more harm than good when touching the header (to expand quick
// settings), so disable it for this view
@@ -162,16 +165,19 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
}
private void setBuildText() {
- TextView v = findViewById(R.id.build);
- if (v == null) return;
+ if (mBuildText == null) return;
if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) {
- v.setText(mContext.getString(
+ mBuildText.setText(mContext.getString(
com.android.internal.R.string.bugreport_status,
Build.VERSION.RELEASE_OR_CODENAME,
Build.ID));
- v.setVisibility(View.VISIBLE);
+ // Set as selected for marquee before its made visible, then it won't be announced when
+ // it's made visible.
+ mBuildText.setSelected(true);
+ mShouldShowBuildText = true;
} else {
- v.setVisibility(View.GONE);
+ mShouldShowBuildText = false;
+ mBuildText.setSelected(false);
}
}
@@ -321,6 +327,8 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
mMultiUserSwitch.setVisibility(showUserSwitcher() ? View.VISIBLE : View.INVISIBLE);
mEditContainer.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
mSettingsButton.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
+
+ mBuildText.setVisibility(mExpanded && mShouldShowBuildText ? View.VISIBLE : View.GONE);
}
private boolean showUserSwitcher() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 795d0627c447..d11079294a85 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -14,6 +14,7 @@
package com.android.systemui.qs.tileimpl;
+import static androidx.lifecycle.Lifecycle.State.DESTROYED;
import static androidx.lifecycle.Lifecycle.State.RESUMED;
import static androidx.lifecycle.Lifecycle.State.STARTED;
@@ -475,6 +476,8 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
}
mCallbacks.clear();
mHandler.removeCallbacksAndMessages(null);
+ // This will force it to be removed from all controllers that may have it registered.
+ mLifecycle.setCurrentState(DESTROYED);
}
protected void checkIfRestrictionEnforcedByAdminOnly(State state, String userRestriction) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 370f9a762402..570a4bb3cd12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -197,7 +197,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
return;
}
mView.setHidden(mKeyguardStateController.isShowing());
- mImePositionProcessor.updateAdjustForIme();
+ if (!mKeyguardStateController.isShowing()) {
+ mImePositionProcessor.updateAdjustForIme();
+ }
}
@Override
@@ -316,7 +318,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
private void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mView.isHidden();
+ final boolean isDividerHidden = mView != null && mKeyguardStateController.isShowing();
removeDivider();
addDivider(configuration);
@@ -529,6 +531,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
updateVisibility(false /* visible */);
mMinimized = false;
removeDivider();
+ mImePositionProcessor.reset();
}
void ensureMinimizedSplit() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 9db389eba3d8..5aeca5e07bdd 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -117,6 +117,18 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
&& (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
}
+ void reset() {
+ mPaused = true;
+ mPausedTargetAdjusted = false;
+ mAdjustedWhileHidden = false;
+ mAnimation = null;
+ mAdjusted = mTargetAdjusted = false;
+ mImeWasShown = mTargetShown = false;
+ mTargetPrimaryDim = mTargetSecondaryDim = mLastPrimaryDim = mLastSecondaryDim = 0.f;
+ mSecondaryHasFocus = false;
+ mLastAdjustTop = -1;
+ }
+
private void updateDimTargets() {
final boolean splitIsVisible = !getView().isHidden();
mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
@@ -126,18 +138,20 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
}
@Override
- public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, SurfaceControl.Transaction t) {
+ @ImeAnimationFlags
+ public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean imeShouldShow, boolean imeIsFloating, SurfaceControl.Transaction t) {
mHiddenTop = hiddenTop;
mShownTop = shownTop;
mTargetShown = imeShouldShow;
if (!isDividerVisible()) {
- return;
+ return 0;
}
final boolean splitIsVisible = !getView().isHidden();
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
- && !getLayout().mDisplayLayout.isLandscape() && !mSplits.mDivider.isMinimized();
+ && !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
+ && !mSplits.mDivider.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -155,7 +169,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
if (mPaused) {
mPausedTargetAdjusted = targetAdjusted;
if (DEBUG) Slog.d(TAG, " ime starting but paused " + dumpState());
- return;
+ return (targetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
}
mTargetAdjusted = targetAdjusted;
updateDimTargets();
@@ -174,6 +188,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
} else {
mAdjustedWhileHidden = true;
}
+ return (mTargetAdjusted || mAdjusted) ? IME_ANIMATION_NO_ALPHA : 0;
}
private void updateImeAdjustState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index cdcfac87f1c8..d264af94947d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -84,7 +84,6 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
private final Map<View, MenuItem> mMenuItemsByView = new ArrayMap<>();
private OnMenuEventListener mMenuListener;
private boolean mDismissRtl;
- private boolean mIsForeground;
private ValueAnimator mFadeAnimator;
private boolean mAnimating;
@@ -191,9 +190,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
@Override
public void createMenu(ViewGroup parent, StatusBarNotification sbn) {
mParent = (ExpandableNotificationRow) parent;
- createMenuViews(true /* resetState */,
- sbn != null && (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)
- != 0);
+ createMenuViews(true /* resetState */);
}
@Override
@@ -237,8 +234,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
// Menu hasn't been created yet, no need to do anything.
return;
}
- createMenuViews(!isMenuVisible() /* resetState */,
- (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0);
+ createMenuViews(!isMenuVisible() /* resetState */);
}
@Override
@@ -253,9 +249,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
mParent.removeListener();
}
- private void createMenuViews(boolean resetState, final boolean isForeground) {
- mIsForeground = isForeground;
-
+ private void createMenuViews(boolean resetState) {
final Resources res = mContext.getResources();
mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
@@ -266,7 +260,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
SHOW_NOTIFICATION_SNOOZE, 0) == 1;
// Construct the menu items based on the notification
- if (!isForeground && showSnooze) {
+ if (showSnooze) {
// Only show snooze for non-foreground notifications, and if the setting is on
mSnoozeItem = createSnoozeItem(mContext);
}
@@ -283,7 +277,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
mInfoItem = createInfoItem(mContext);
}
- if (!isForeground && showSnooze) {
+ if (showSnooze) {
mRightMenuItems.add(mSnoozeItem);
}
mRightMenuItems.add(mInfoItem);
@@ -789,7 +783,7 @@ public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnCl
public void setDismissRtl(boolean dismissRtl) {
mDismissRtl = dismissRtl;
if (mMenuContainer != null) {
- createMenuViews(true, mIsForeground);
+ createMenuViews(true);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index c87b9986ca55..91cc8963b947 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -41,8 +41,8 @@ import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.children
-import com.android.systemui.util.takeUntil
import com.android.systemui.util.foldToSparseArray
+import com.android.systemui.util.takeUntil
import javax.inject.Inject
/**
@@ -166,6 +166,9 @@ class NotificationSectionsManager @Inject internal constructor(
peopleHubSubscription?.unsubscribe()
peopleHubSubscription = null
peopleHeaderView = reinflateView(peopleHeaderView, layoutInflater, R.layout.people_strip)
+ .apply {
+ setOnHeaderClickListener(View.OnClickListener { onGentleHeaderClick() })
+ }
if (ENABLE_SNOOZED_CONVERSATION_HUB) {
peopleHubSubscription = peopleHubViewAdapter.bindView(peopleHubViewBoundary)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
index 8f77a1d776e4..b13e7fb839ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
@@ -93,6 +93,8 @@ class PeopleHubView(context: Context, attrs: AttributeSet) :
}
}
+ fun setOnHeaderClickListener(listener: OnClickListener) = label.setOnClickListener(listener)
+
private inner class PersonDataListenerImpl(val avatarView: ImageView) :
DataListener<PersonViewModel?> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index e03db2c8b9c6..39f5847ce2a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -14,6 +14,7 @@
package com.android.systemui.statusbar.phone;
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_CLOCK;
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
@@ -63,6 +64,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private View mNotificationIconAreaInner;
private View mCenteredIconArea;
private int mDisabled1;
+ private int mDisabled2;
private StatusBar mStatusBarComponent;
private DarkIconManager mDarkIconManager;
private View mOperatorNameFrame;
@@ -173,9 +175,12 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
state1 = adjustDisableFlags(state1);
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
+ final int old2 = mDisabled2;
+ final int diff2 = state2 ^ old2;
mDisabled1 = state1;
- if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
- if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
+ mDisabled2 = state2;
+ if ((diff1 & DISABLE_SYSTEM_INFO) != 0 || ((diff2 & DISABLE2_SYSTEM_ICONS) != 0)) {
+ if ((state1 & DISABLE_SYSTEM_INFO) != 0 || ((state2 & DISABLE2_SYSTEM_ICONS) != 0)) {
hideSystemIconArea(animate);
hideOperatorName(animate);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 27daf8615a31..b7733cc5acd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -591,6 +591,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
.registerDisplayListener(this, new Handler(Looper.getMainLooper()));
mOrientationHandle = new QuickswitchOrientedNavHandle(getContext());
+ mOrientationHandle.setId(R.id.secondary_home_handle);
getBarTransitions().addDarkIntensityListener(mOrientationHandleIntensityListener);
mOrientationParams = new WindowManager.LayoutParams(0, 0,
@@ -962,13 +963,22 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
// Change the cancel pin gesture to home and back if recents button is invisible
- boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
+ boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
- if (recentsVisible) {
- backButton.setOnLongClickListener(this::onLongPressBackRecents);
+ ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+ if (pinningActive) {
+ boolean recentsVisible = mNavigationBarView.isRecentsButtonVisible();
+ backButton.setOnLongClickListener(recentsVisible
+ ? this::onLongPressBackRecents
+ : this::onLongPressBackHome);
+ recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
} else {
- backButton.setOnLongClickListener(this::onLongPressBackHome);
+ backButton.setOnLongClickListener(null);
+ recentsButton.setOnLongClickListener(null);
}
+ // Note, this needs to be set after even if we're setting the listener to null
+ backButton.setLongClickable(pinningActive);
+ recentsButton.setLongClickable(pinningActive);
}
private void notifyNavigationBarScreenOn() {
@@ -981,11 +991,6 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
recentsButton.setOnClickListener(this::onRecentsClick);
recentsButton.setOnTouchListener(this::onRecentsTouch);
- recentsButton.setLongClickable(true);
- recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
-
- ButtonDispatcher backButton = mNavigationBarView.getBackButton();
- backButton.setLongClickable(true);
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
@@ -1093,6 +1098,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
}
+
/**
* This handles long-press of both back and recents/home. Back is the common button with
* combination of recents if it is visible or home if recents is invisible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 07eaaa187fbe..bf858520c338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -19,8 +19,6 @@ package com.android.systemui.statusbar.phone;
import static com.android.systemui.statusbar.phone.HeadsUpAppearanceController.CONTENT_FADE_DELAY;
import static com.android.systemui.statusbar.phone.HeadsUpAppearanceController.CONTENT_FADE_DURATION;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
@@ -807,6 +805,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
} else {
super.applyToView(view);
}
+ sTempProperties.setAnimationEndAction(null);
boolean inShelf = iconAppearAmount == 1.0f;
icon.setIsInShelf(inShelf);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 5164440c1463..bc73be19ab59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -61,6 +61,8 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -432,7 +434,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
}
private void applyHasTopUi(State state) {
- mHasTopUiChanged = state.mForceHasTopUi || isExpanded(state);
+ mHasTopUiChanged = !state.mComponentsForcingTopUi.isEmpty() || isExpanded(state);
}
private void applyNotTouchable(State state) {
@@ -635,12 +637,17 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
apply(mCurrentState);
}
- public boolean getForceHasTopUi() {
- return mCurrentState.mForceHasTopUi;
- }
-
- public void setForceHasTopUi(boolean forceHasTopUi) {
- mCurrentState.mForceHasTopUi = forceHasTopUi;
+ /**
+ * SystemUI may need top-ui to avoid jank when performing animations. After the
+ * animation is performed, the component should remove itself from the list of features that
+ * are forcing SystemUI to be top-ui.
+ */
+ public void setRequestTopUi(boolean requestTopUi, String componentTag) {
+ if (requestTopUi) {
+ mCurrentState.mComponentsForcingTopUi.add(componentTag);
+ } else {
+ mCurrentState.mComponentsForcingTopUi.remove(componentTag);
+ }
apply(mCurrentState);
}
@@ -663,7 +670,7 @@ public class NotificationShadeWindowController implements Callback, Dumpable,
boolean mBackdropShowing;
boolean mWallpaperSupportsAmbientMode;
boolean mNotTouchable;
- boolean mForceHasTopUi;
+ Set<String> mComponentsForcingTopUi = new HashSet<>();
/**
* The {@link StatusBar} state from the status bar.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c14a5ef328aa..8ee0bdf2938a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -18,6 +18,9 @@ package com.android.systemui.statusbar.phone;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_CLOCK;
+import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
@@ -213,7 +216,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -306,6 +308,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public static final int FADE_KEYGUARD_DURATION = 300;
public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
+
/** If true, the system is in the half-boot-to-decryption-screen state.
* Prudently disable QS and notifications. */
public static final boolean ONLY_CORE_APPS;
@@ -2397,18 +2400,31 @@ public class StatusBar extends SystemUI implements DemoMode,
new WirelessChargingAnimation.Callback() {
@Override
public void onAnimationStarting() {
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
CrossFadeHelper.fadeOut(mNotificationPanelViewController.getView(), 1);
}
@Override
public void onAnimationEnded() {
CrossFadeHelper.fadeIn(mNotificationPanelViewController.getView());
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
}
}, mDozing).show(animationDelay);
} else {
// workspace
WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
- transmittingBatteryLevel, batteryLevel, null, false).show(animationDelay);
+ transmittingBatteryLevel, batteryLevel,
+ new WirelessChargingAnimation.Callback() {
+ @Override
+ public void onAnimationStarting() {
+ mNotificationShadeWindowController.setRequestTopUi(true, TAG);
+ }
+
+ @Override
+ public void onAnimationEnded() {
+ mNotificationShadeWindowController.setRequestTopUi(false, TAG);
+ }
+ }, false).show(animationDelay);
}
}
@@ -4165,6 +4181,7 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) {
mTopHidesStatusBar = topAppHidesStatusBar;
+ updateStatusBarIcons(topAppHidesStatusBar);
if (!topAppHidesStatusBar && mWereIconsJustHidden) {
// Immediately update the icon hidden state, since that should only apply if we're
// staying fullscreen.
@@ -4174,6 +4191,17 @@ public class StatusBar extends SystemUI implements DemoMode,
updateHideIconsForBouncer(true /* animate */);
}
+ private void updateStatusBarIcons(boolean topAppHidesStatusBar) {
+ int flags1 = StatusBarManager.DISABLE_NONE;
+ int flags2 = StatusBarManager.DISABLE2_NONE;
+ if (topAppHidesStatusBar) {
+ flags1 = DISABLE_NOTIFICATION_ICONS | DISABLE_CLOCK;
+ flags2 = DISABLE2_SYSTEM_ICONS;
+ }
+
+ mCommandQueue.disable(mDisplayId, flags1, flags2, false);
+ }
+
protected void toggleKeyboardShortcuts(int deviceId) {
KeyboardShortcuts.toggle(mContext, deviceId);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 93df14f18fda..3ae84ecfc2f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -14,9 +14,6 @@
package com.android.systemui.statusbar.phone;
-import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
-import static android.app.StatusBarManager.DISABLE_NONE;
-
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
@@ -47,7 +44,6 @@ import com.android.systemui.statusbar.StatusBarWifiView;
import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
-import com.android.systemui.util.Utils.DisableStateTracker;
import java.util.List;
@@ -218,14 +214,6 @@ public interface StatusBarIconController {
mContext = group.getContext();
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
-
- DisableStateTracker tracker =
- new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS, commandQueue);
- mGroup.addOnAttachStateChangeListener(tracker);
- if (mGroup.isAttachedToWindow()) {
- // In case we miss the first onAttachedToWindow event
- tracker.onViewAttachedToWindow(mGroup);
- }
}
public boolean isDemoable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 8fcaa67e7614..23d03a4b225a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -80,6 +80,22 @@ public class KeyButtonDrawable extends Drawable {
private final Paint mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
private final ShadowDrawableState mState;
private AnimatedVectorDrawable mAnimatedDrawable;
+ private final Callback mAnimatedDrawableCallback = new Callback() {
+ @Override
+ public void invalidateDrawable(@NonNull Drawable who) {
+ invalidateSelf();
+ }
+
+ @Override
+ public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) {
+ scheduleSelf(what, when);
+ }
+
+ @Override
+ public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) {
+ unscheduleSelf(what);
+ }
+ };
public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
boolean horizontalFlip, Color ovalBackgroundColor) {
@@ -97,6 +113,7 @@ public class KeyButtonDrawable extends Drawable {
}
if (canAnimate()) {
mAnimatedDrawable = (AnimatedVectorDrawable) mState.mChildState.newDrawable().mutate();
+ mAnimatedDrawable.setCallback(mAnimatedDrawableCallback);
setDrawableBounds(mAnimatedDrawable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 18a7adda3f7d..cf83603997c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -284,6 +284,9 @@ public class MobileSignalController extends SignalController<
mNetworkToIconLookup.put(toDisplayIconKey(
TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE),
TelephonyIcons.NR_5G_PLUS);
+ mNetworkToIconLookup.put(toIconKey(
+ TelephonyManager.NETWORK_TYPE_NR),
+ TelephonyIcons.NR_5G);
}
private String getIconKey() {
@@ -306,9 +309,9 @@ public class MobileSignalController extends SignalController<
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO:
return toIconKey(TelephonyManager.NETWORK_TYPE_LTE) + "_CA_Plus";
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA:
- return "5G";
+ return toIconKey(TelephonyManager.NETWORK_TYPE_NR);
case TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE:
- return "5G_Plus";
+ return toIconKey(TelephonyManager.NETWORK_TYPE_NR) + "_Plus";
default:
return "unsupported";
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 53ac65700a05..9c3395f9332d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -79,7 +79,7 @@ import java.util.function.Consumer;
/**
* Host for the remote input.
*/
-public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
+public class RemoteInputView extends LinearLayout implements View.OnClickListener {
private static final String TAG = "RemoteInput";
@@ -88,6 +88,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
public final Object mToken = new Object();
+ private final SendButtonTextWatcher mTextWatcher;
+ private final TextView.OnEditorActionListener mEditorActionHandler;
private RemoteEditText mEditText;
private ImageButton mSendButton;
private ProgressBar mProgressBar;
@@ -113,6 +115,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
public RemoteInputView(Context context, AttributeSet attrs) {
super(context, attrs);
+ mTextWatcher = new SendButtonTextWatcher();
+ mEditorActionHandler = new EditorActionHandler();
mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
mStatusBarManagerService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -128,30 +132,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mSendButton.setOnClickListener(this);
mEditText = (RemoteEditText) getChildAt(0);
- mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- final boolean isSoftImeEvent = event == null
- && (actionId == EditorInfo.IME_ACTION_DONE
- || actionId == EditorInfo.IME_ACTION_NEXT
- || actionId == EditorInfo.IME_ACTION_SEND);
- final boolean isKeyboardEnterKey = event != null
- && KeyEvent.isConfirmKey(event.getKeyCode())
- && event.getAction() == KeyEvent.ACTION_DOWN;
-
- if (isSoftImeEvent || isKeyboardEnterKey) {
- if (mEditText.length() > 0) {
- sendRemoteInput(prepareRemoteInputFromText());
- }
- // Consume action to prevent IME from closing.
- return true;
- }
- return false;
- }
- });
- mEditText.addTextChangedListener(this);
mEditText.setInnerFocusable(false);
- mEditText.mRemoteInputView = this;
}
protected Intent prepareRemoteInputFromText() {
@@ -292,6 +273,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mEditText.mRemoteInputView = this;
+ mEditText.setOnEditorActionListener(mEditorActionHandler);
+ mEditText.addTextChangedListener(mTextWatcher);
if (mEntry.getRow().isChangingPosition()) {
if (getVisibility() == VISIBLE && mEditText.isFocusable()) {
mEditText.requestFocus();
@@ -302,6 +286,9 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ mEditText.removeTextChangedListener(mTextWatcher);
+ mEditText.setOnEditorActionListener(null);
+ mEditText.mRemoteInputView = null;
if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) {
return;
}
@@ -412,17 +399,6 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
mSendButton.setEnabled(mEditText.getText().length() != 0);
}
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {}
-
- @Override
- public void afterTextChanged(Editable s) {
- updateSendButton();
- }
-
public void close() {
mEditText.defocusIfNeeded(false /* animated */);
}
@@ -545,6 +521,45 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
return getVisibility() == VISIBLE && mController.isSpinning(mEntry.getKey(), mToken);
}
+ /** Handler for button click on send action in IME. */
+ private class EditorActionHandler implements TextView.OnEditorActionListener {
+
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ final boolean isSoftImeEvent = event == null
+ && (actionId == EditorInfo.IME_ACTION_DONE
+ || actionId == EditorInfo.IME_ACTION_NEXT
+ || actionId == EditorInfo.IME_ACTION_SEND);
+ final boolean isKeyboardEnterKey = event != null
+ && KeyEvent.isConfirmKey(event.getKeyCode())
+ && event.getAction() == KeyEvent.ACTION_DOWN;
+
+ if (isSoftImeEvent || isKeyboardEnterKey) {
+ if (mEditText.length() > 0) {
+ sendRemoteInput(prepareRemoteInputFromText());
+ }
+ // Consume action to prevent IME from closing.
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /** Observes text change events and updates the visibility of the send button accordingly. */
+ private class SendButtonTextWatcher implements TextWatcher {
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateSendButton();
+ }
+ }
+
/**
* An EditText that changes appearance based on whether it's focusable and becomes
* un-focusable whenever the user navigates away from it or it becomes invisible.
@@ -599,7 +614,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
if (!focused) {
defocusIfNeeded(true /* animate */);
}
- if (!mRemoteInputView.mRemoved) {
+ if (mRemoteInputView != null && !mRemoteInputView.mRemoved) {
mLightBarController.setDirectReplying(focused);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 6bc0565510a2..c0602762ef29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -26,6 +26,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.statusbar.CommandQueue;
@@ -72,6 +73,11 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
+
+ if (mContext.getResources().getBoolean(R.bool.audio_recording_disclosure_enabled)) {
+ // Creating AudioRecordingDisclosureBar and just letting it run
+ new AudioRecordingDisclosureBar(mContext);
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index 36e360da857f..8e4e12358836 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -112,6 +112,13 @@ public class AudioRecordingDisclosureBar implements
*/
private final AudioActivityObserver[] mAudioActivityObservers;
/**
+ * Whether the indicator should expand and show the recording application's label.
+ * If disabled ({@code false}) the "minimized" ({@link #STATE_MINIMIZED}) indicator would appear
+ * on the screen whenever an application is recording, but will not reveal to the user what
+ * application this is.
+ */
+ private final boolean mRevealRecordingPackages;
+ /**
* Set of applications that we've notified the user about since the indicator came up. Meaning
* that if an application is in this list then at some point since the indicator came up, it
* was expanded showing this application's title.
@@ -137,6 +144,8 @@ public class AudioRecordingDisclosureBar implements
public AudioRecordingDisclosureBar(Context context) {
mContext = context;
+ mRevealRecordingPackages = mContext.getResources().getBoolean(
+ R.bool.audio_recording_disclosure_reveal_packages);
mExemptPackages = new ArraySet<>(
Arrays.asList(mContext.getResources().getStringArray(
R.array.audio_recording_disclosure_exempt_apps)));
@@ -149,11 +158,6 @@ public class AudioRecordingDisclosureBar implements
};
}
- private String[] getGlobalStringArray(String setting) {
- String result = Settings.Global.getString(mContext.getContentResolver(), setting);
- return TextUtils.isEmpty(result) ? new String[0] : result.split(",");
- }
-
@UiThread
@Override
public void onAudioActivityStateChange(boolean active, String packageName) {
@@ -190,7 +194,9 @@ public class AudioRecordingDisclosureBar implements
break;
case STATE_MINIMIZED:
- expand(packageName);
+ if (mRevealRecordingPackages) {
+ expand(packageName);
+ }
break;
case STATE_DISAPPEARING:
@@ -228,9 +234,8 @@ public class AudioRecordingDisclosureBar implements
@UiThread
private void show(String packageName) {
- final String label = getApplicationLabel(packageName);
if (DEBUG) {
- Log.d(TAG, "Showing indicator for " + packageName + " (" + label + ")...");
+ Log.d(TAG, "Showing indicator for " + packageName);
}
mIsLtr = mContext.getResources().getConfiguration().getLayoutDirection()
@@ -247,19 +252,31 @@ public class AudioRecordingDisclosureBar implements
mTextView = mTextsContainers.findViewById(R.id.text);
mBgEnd = mIndicatorView.findViewById(R.id.bg_end);
- // Swap background drawables depending on layout directions (both drawables have rounded
- // corners only on one side)
- if (mIsLtr) {
- mBgEnd.setBackgroundResource(R.drawable.tv_rect_dark_right_rounded);
- mIconContainerBg.setBackgroundResource(R.drawable.tv_rect_dark_left_rounded);
+ // Set up the notification text
+ if (mRevealRecordingPackages) {
+ // Swap background drawables depending on layout directions (both drawables have rounded
+ // corners only on one side)
+ if (mIsLtr) {
+ mBgEnd.setBackgroundResource(R.drawable.tv_rect_dark_right_rounded);
+ mIconContainerBg.setBackgroundResource(R.drawable.tv_rect_dark_left_rounded);
+ } else {
+ mBgEnd.setBackgroundResource(R.drawable.tv_rect_dark_left_rounded);
+ mIconContainerBg.setBackgroundResource(R.drawable.tv_rect_dark_right_rounded);
+ }
+
+ final String label = getApplicationLabel(packageName);
+ mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
} else {
- mBgEnd.setBackgroundResource(R.drawable.tv_rect_dark_left_rounded);
- mIconContainerBg.setBackgroundResource(R.drawable.tv_rect_dark_right_rounded);
+ mTextsContainers.setVisibility(View.GONE);
+ mIconContainerBg.setVisibility(View.GONE);
+ mTextView.setVisibility(View.GONE);
+ mBgEnd.setVisibility(View.GONE);
+ mTextsContainers = null;
+ mIconContainerBg = null;
+ mTextView = null;
+ mBgEnd = null;
}
- // Set up the notification text
- mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
-
// Initially change the visibility to INVISIBLE, wait until and receives the size and
// then animate it moving from "off" the screen correctly
mIndicatorView.setVisibility(View.INVISIBLE);
@@ -296,7 +313,11 @@ public class AudioRecordingDisclosureBar implements
@Override
public void onAnimationEnd(Animator animation) {
startPulsatingAnimation();
- onExpanded();
+ if (mRevealRecordingPackages) {
+ onExpanded();
+ } else {
+ onMinimized();
+ }
}
});
set.start();
@@ -321,6 +342,8 @@ public class AudioRecordingDisclosureBar implements
@UiThread
private void expand(String packageName) {
+ assertRevealingRecordingPackages();
+
final String label = getApplicationLabel(packageName);
if (DEBUG) {
Log.d(TAG, "Expanding for " + packageName + " (" + label + ")...");
@@ -348,6 +371,8 @@ public class AudioRecordingDisclosureBar implements
@UiThread
private void minimize() {
+ assertRevealingRecordingPackages();
+
if (DEBUG) Log.d(TAG, "Minimizing...");
final int targetOffset = (mIsLtr ? 1 : -1) * mTextsContainers.getWidth();
final AnimatorSet set = new AnimatorSet();
@@ -393,6 +418,8 @@ public class AudioRecordingDisclosureBar implements
@UiThread
private void onExpanded() {
+ assertRevealingRecordingPackages();
+
if (DEBUG) Log.d(TAG, "Expanded");
mState = STATE_SHOWN;
@@ -404,11 +431,13 @@ public class AudioRecordingDisclosureBar implements
if (DEBUG) Log.d(TAG, "Minimized");
mState = STATE_MINIMIZED;
- if (!mPendingNotificationPackages.isEmpty()) {
- // There is a new application that started recording, tell the user about it.
- expand(mPendingNotificationPackages.poll());
- } else {
- hideIndicatorIfNeeded();
+ if (mRevealRecordingPackages) {
+ if (!mPendingNotificationPackages.isEmpty()) {
+ // There is a new application that started recording, tell the user about it.
+ expand(mPendingNotificationPackages.poll());
+ } else {
+ hideIndicatorIfNeeded();
+ }
}
}
@@ -451,7 +480,14 @@ public class AudioRecordingDisclosureBar implements
animator.start();
}
+ private String[] getGlobalStringArray(String setting) {
+ String result = Settings.Global.getString(mContext.getContentResolver(), setting);
+ return TextUtils.isEmpty(result) ? new String[0] : result.split(",");
+ }
+
private String getApplicationLabel(String packageName) {
+ assertRevealingRecordingPackages();
+
final PackageManager pm = mContext.getPackageManager();
final ApplicationInfo appInfo;
try {
@@ -461,4 +497,11 @@ public class AudioRecordingDisclosureBar implements
}
return pm.getApplicationLabel(appInfo).toString();
}
+
+ private void assertRevealingRecordingPackages() {
+ if (!mRevealRecordingPackages) {
+ Log.e(TAG, "Not revealing recording packages",
+ DEBUG ? new RuntimeException("Should not be called") : null);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
index a31ea7c3ab17..8946c97a4b58 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
@@ -40,7 +40,7 @@ public class DismissCircleView extends FrameLayout {
setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
- mIconView.setImageDrawable(res.getDrawable(R.drawable.ic_close_white));
+ mIconView.setImageDrawable(res.getDrawable(R.drawable.pip_ic_close_white));
addView(mIconView);
setViewSizes();
diff --git a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
index 016f4de724b6..2a5424ce4ef7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/animation/PhysicsAnimator.kt
@@ -20,6 +20,7 @@ import android.os.Looper
import android.util.ArrayMap
import android.util.Log
import android.view.View
+import androidx.dynamicanimation.animation.AnimationHandler
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FlingAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -124,6 +125,12 @@ class PhysicsAnimator<T> private constructor (target: T) {
private var defaultFling: FlingConfig = globalDefaultFling
/**
+ * AnimationHandler to use if it need custom AnimationHandler, if this is null, it will use
+ * the default AnimationHandler in the DynamicAnimation.
+ */
+ private var customAnimationHandler: AnimationHandler? = null
+
+ /**
* Internal listeners that respond to DynamicAnimations updating and ending, and dispatch to
* the listeners provided via [addUpdateListener] and [addEndListener]. This allows us to add
* just one permanent update and end listener to the DynamicAnimations.
@@ -447,6 +454,14 @@ class PhysicsAnimator<T> private constructor (target: T) {
this.defaultFling = defaultFling
}
+ /**
+ * Set the custom AnimationHandler for all aniatmion in this animator. Set this with null for
+ * restoring to default AnimationHandler.
+ */
+ fun setCustomAnimationHandler(handler: AnimationHandler) {
+ this.customAnimationHandler = handler
+ }
+
/** Starts the animations! */
fun start() {
startAction()
@@ -501,10 +516,13 @@ class PhysicsAnimator<T> private constructor (target: T) {
// springs) on this property before flinging.
cancel(animatedProperty)
+ // Apply the custom animation handler if it not null
+ val flingAnim = getFlingAnimation(animatedProperty, target)
+ flingAnim.animationHandler =
+ customAnimationHandler ?: flingAnim.animationHandler
+
// Apply the configuration and start the animation.
- getFlingAnimation(animatedProperty, target)
- .also { flingConfig.applyToAnimation(it) }
- .start()
+ flingAnim.also { flingConfig.applyToAnimation(it) }.start()
}
}
@@ -516,6 +534,21 @@ class PhysicsAnimator<T> private constructor (target: T) {
if (flingConfig == null) {
// Apply the configuration and start the animation.
val springAnim = getSpringAnimation(animatedProperty, target)
+
+ // If customAnimationHander is exist and has not been set to the animation,
+ // it should set here.
+ if (customAnimationHandler != null &&
+ springAnim.animationHandler != customAnimationHandler) {
+ // Cancel the animation before set animation handler
+ if (springAnim.isRunning) {
+ cancel(animatedProperty)
+ }
+ // Apply the custom animation handler if it not null
+ springAnim.animationHandler =
+ customAnimationHandler ?: springAnim.animationHandler
+ }
+
+ // Apply the configuration and start the animation.
springConfig.applyToAnimation(springAnim)
animationStartActions.add(springAnim::start)
} else {
@@ -570,10 +603,13 @@ class PhysicsAnimator<T> private constructor (target: T) {
}
}
+ // Apply the custom animation handler if it not null
+ val springAnim = getSpringAnimation(animatedProperty, target)
+ springAnim.animationHandler =
+ customAnimationHandler ?: springAnim.animationHandler
+
// Apply the configuration and start the spring animation.
- getSpringAnimation(animatedProperty, target)
- .also { springConfig.applyToAnimation(it) }
- .start()
+ springAnim.also { springConfig.applyToAnimation(it) }.start()
}
}
})
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 3402a52f056a..89f469a438a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -19,6 +19,7 @@ package com.android.systemui.wm;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
@@ -136,12 +137,16 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
}
}
- private void dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean show, SurfaceControl.Transaction t) {
+ @ImePositionProcessor.ImeAnimationFlags
+ private int dispatchStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean show, boolean isFloating, SurfaceControl.Transaction t) {
synchronized (mPositionProcessors) {
+ int flags = 0;
for (ImePositionProcessor pp : mPositionProcessors) {
- pp.onImeStartPositioning(displayId, hiddenTop, shownTop, show, t);
+ flags |= pp.onImeStartPositioning(
+ displayId, hiddenTop, shownTop, show, isFloating, t);
}
+ return flags;
}
}
@@ -184,6 +189,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
int mRotation = Surface.ROTATION_0;
boolean mImeShowing = false;
final Rect mImeFrame = new Rect();
+ boolean mAnimateAlpha = true;
PerDisplay(int displayId, int initialRotation) {
mDisplayId = displayId;
@@ -273,15 +279,29 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return mImeFrame.top + (int) surfaceOffset;
}
+ private boolean calcIsFloating(InsetsSource imeSource) {
+ final Rect frame = imeSource.getFrame();
+ if (frame.height() == 0) {
+ return true;
+ }
+ // Some Floating Input Methods will still report a frame, but the frame is actually
+ // a nav-bar inset created by WM and not part of the IME (despite being reported as
+ // an IME inset). For now, we assume that no non-floating IME will be <= this nav bar
+ // frame height so any reported frame that is <= nav-bar frame height is assumed to
+ // be floating.
+ return frame.height() <= mSystemWindows.mDisplayController.getDisplayLayout(mDisplayId)
+ .navBarFrameHeight();
+ }
+
private void startAnimation(final boolean show, final boolean forceRestart) {
final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
if (imeSource == null || mImeSourceControl == null) {
return;
}
final Rect newFrame = imeSource.getFrame();
- final boolean isFloating = newFrame.height() == 0 && show;
+ final boolean isFloating = calcIsFloating(imeSource) && show;
if (isFloating) {
- // This is likely a "floating" or "expanded" IME, so to get animations, just
+ // This is a "floating" or "expanded" IME, so to get animations, just
// pretend the ime has some size just below the screen.
mImeFrame.set(newFrame);
final int floatingInset = (int) (
@@ -334,7 +354,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
SurfaceControl.Transaction t = mTransactionPool.acquire();
float value = (float) animation.getAnimatedValue();
t.setPosition(mImeSourceControl.getLeash(), x, value);
- final float alpha = isFloating ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (value - hiddenY) / (shownY - hiddenY) : 1.f;
t.setAlpha(mImeSourceControl.getLeash(), alpha);
dispatchPositionChanged(mDisplayId, imeTop(value), t);
t.apply();
@@ -347,16 +368,18 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public void onAnimationStart(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
t.setPosition(mImeSourceControl.getLeash(), x, startY);
- final float alpha = isFloating ? (startY - hiddenY) / (shownY - hiddenY) : 1.f;
- t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (DEBUG) {
Slog.d(TAG, "onAnimationStart d:" + mDisplayId + " top:"
+ imeTop(hiddenY) + "->" + imeTop(shownY)
+ " showing:" + (mAnimationDirection == DIRECTION_SHOW));
}
- dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
- imeTop(shownY), mAnimationDirection == DIRECTION_SHOW,
- t);
+ int flags = dispatchStartPositioning(mDisplayId, imeTop(hiddenY),
+ imeTop(shownY), mAnimationDirection == DIRECTION_SHOW, isFloating, t);
+ mAnimateAlpha = (flags & ImePositionProcessor.IME_ANIMATION_NO_ALPHA) == 0;
+ final float alpha = (mAnimateAlpha || isFloating)
+ ? (startY - hiddenY) / (shownY - hiddenY)
+ : 1.f;
+ t.setAlpha(mImeSourceControl.getLeash(), alpha);
if (mAnimationDirection == DIRECTION_SHOW) {
t.show(mImeSourceControl.getLeash());
}
@@ -419,15 +442,33 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
*/
public interface ImePositionProcessor {
/**
+ * Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff
+ * behind the IME shouldn't be visible (for example during split-screen adjustment where
+ * there is nothing behind the ime).
+ */
+ int IME_ANIMATION_NO_ALPHA = 1;
+
+ /** @hide */
+ @IntDef(prefix = { "IME_ANIMATION_" }, value = {
+ IME_ANIMATION_NO_ALPHA,
+ })
+ @interface ImeAnimationFlags {}
+
+ /**
* Called when the IME position is starting to animate.
*
* @param hiddenTop The y position of the top of the IME surface when it is hidden.
* @param shownTop The y position of the top of the IME surface when it is shown.
* @param showing {@code true} when we are animating from hidden to shown, {@code false}
* when animating from shown to hidden.
+ * @param isFloating {@code true} when the ime is a floating ime (doesn't inset).
+ * @return flags that may alter how ime itself is animated (eg. no-alpha).
*/
- default void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean showing, SurfaceControl.Transaction t) {}
+ @ImeAnimationFlags
+ default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
+ return 0;
+ }
/**
* Called when the ime position changed. This is expected to be a synchronous call on the
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
index cfec1c07ff1d..a341f3050ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -79,6 +79,7 @@ public class DisplayLayout {
private final Rect mStableInsets = new Rect();
private boolean mHasNavigationBar = false;
private boolean mHasStatusBar = false;
+ private int mNavBarFrameHeight = 0;
/**
* Create empty layout.
@@ -146,6 +147,7 @@ public class DisplayLayout {
if (mHasStatusBar) {
convertNonDecorInsetsToStableInsets(res, mStableInsets, mWidth, mHeight, mHasStatusBar);
}
+ mNavBarFrameHeight = getNavigationBarFrameHeight(res, mWidth > mHeight);
}
/**
@@ -214,6 +216,11 @@ public class DisplayLayout {
return mWidth > mHeight;
}
+ /** Get the navbar frame height (used by ime). */
+ public int navBarFrameHeight() {
+ return mNavBarFrameHeight;
+ }
+
/** Gets the orientation of this layout */
public int getOrientation() {
return (mWidth > mHeight) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
@@ -483,6 +490,7 @@ public class DisplayLayout {
} else {
return res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
}
+
} else {
if (navBarSide == NAV_BAR_BOTTOM) {
return res.getDimensionPixelSize(landscape
@@ -493,4 +501,11 @@ public class DisplayLayout {
}
}
}
+
+ /** @see com.android.server.wm.DisplayPolicy#getNavigationBarFrameHeight */
+ public static int getNavigationBarFrameHeight(Resources res, boolean landscape) {
+ return res.getDimensionPixelSize(landscape
+ ? R.dimen.navigation_bar_frame_height_landscape
+ : R.dimen.navigation_bar_frame_height);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index c36bb0472240..5f153f86d322 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -52,6 +52,7 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.face.FaceManager;
+import android.hardware.face.FaceSensorProperties;
import android.hardware.fingerprint.FingerprintManager;
import android.media.AudioManager;
import android.os.Bundle;
@@ -174,6 +175,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mFaceManager.getSensorProperties()).thenReturn(new FaceSensorProperties());
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
when(mUserManager.isPrimaryUser()).thenReturn(true);
when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class));
@@ -419,6 +423,42 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
@Test
+ public void testTriesToAuthenticateFingerprint_whenKeyguard() {
+ mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
+ mTestableLooper.processAllMessages();
+
+ verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt(), any());
+ }
+
+ @Test
+ public void testFingerprintDoesNotAuth_whenEncrypted() {
+ testFingerprintWhenStrongAuth(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+ }
+
+ @Test
+ public void testFingerprintDoesNotAuth_whenDpmLocked() {
+ testFingerprintWhenStrongAuth(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW);
+ }
+
+ @Test
+ public void testFingerprintDoesNotAuth_whenUserLockdown() {
+ testFingerprintWhenStrongAuth(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ }
+
+ private void testFingerprintWhenStrongAuth(int strongAuth) {
+ when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
+ mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
+ mTestableLooper.processAllMessages();
+
+ verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt());
+ verify(mFingerprintManager).detectFingerprint(any(), any(), anyInt(), any());
+ }
+
+ @Test
public void testTriesToAuthenticate_whenBouncer() {
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
new file mode 100644
index 000000000000..71f3d5bee225
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.accessibility;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+
+import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class MagnificationModeSwitchTest extends SysuiTestCase {
+
+ @Mock
+ private ImageView mMockImageView;
+ @Mock
+ private WindowManager mWindowManager;
+ @Mock
+ private ViewPropertyAnimator mViewPropertyAnimator;
+ private MagnificationModeSwitch mMagnificationModeSwitch;
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
+
+ when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.setStartDelay(anyLong())).thenReturn(mViewPropertyAnimator);
+ when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
+ mViewPropertyAnimator);
+
+ when(mMockImageView.animate()).thenReturn(mViewPropertyAnimator);
+
+ mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mMockImageView);
+ }
+
+ @Test
+ public void removeButton_removeView() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+
+ mMagnificationModeSwitch.removeButton();
+
+ verify(mWindowManager).removeView(mMockImageView);
+ // First invocation is in showButton.
+ verify(mViewPropertyAnimator, times(2)).cancel();
+ }
+
+ @Test
+ public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+
+ verify(mMockImageView).setAlpha(1.0f);
+ verify(mMockImageView).setImageResource(
+ getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ verify(mViewPropertyAnimator).cancel();
+ verify(mViewPropertyAnimator).setDuration(anyLong());
+ verify(mViewPropertyAnimator).setStartDelay(anyLong());
+ verify(mViewPropertyAnimator).alpha(anyFloat());
+ ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mViewPropertyAnimator).withEndAction(captor.capture());
+ verify(mWindowManager).addView(eq(mMockImageView), any(WindowManager.LayoutParams.class));
+
+ captor.getValue().run();
+
+ // First invocation is in showButton.
+ verify(mViewPropertyAnimator, times(2)).cancel();
+ verify(mWindowManager).removeView(mMockImageView);
+ }
+
+ @Test
+ public void performClick_fullscreenMode_removeViewAndChangeSettingsValue() {
+ ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(
+ View.OnClickListener.class);
+ verify(mMockImageView).setOnClickListener(captor.capture());
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+ captor.getValue().onClick(mMockImageView);
+
+ // First invocation is in showButton.
+ verify(mViewPropertyAnimator, times(2)).cancel();
+ verify(mMockImageView).setImageResource(
+ getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
+ verify(mWindowManager).removeView(mMockImageView);
+ final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, actualMode);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 7cf351f3efdd..84a261b6e7d2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -44,6 +44,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.wm.DisplayController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -135,6 +136,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
assertThat(mDisplayAreaOrganizer.mDisplayAreaMap.containsKey(mDisplayAreaInfo)).isTrue();
}
+ @Ignore("b/160848002")
@Test
public void testScheduleOffset() {
final int xOffSet = 0;
@@ -148,6 +150,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer.MSG_OFFSET_ANIMATE)).isEqualTo(true);
}
+ @Ignore("b/160848002")
@Test
public void testRotation_portraitToLandscape() {
when(mMockLeash.isValid()).thenReturn(false);
@@ -180,6 +183,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
}
+ @Ignore("b/160848002")
@Test
public void testRotation_landscapeToPortrait() {
when(mMockLeash.isValid()).thenReturn(false);
@@ -212,6 +216,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
}
+ @Ignore("b/160848002")
@Test
public void testRotation_portraitToPortrait() {
when(mMockLeash.isValid()).thenReturn(false);
@@ -244,6 +249,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
}
+ @Ignore("b/160848002")
@Test
public void testRotation_landscapeToLandscape() {
when(mMockLeash.isValid()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 536cae4380c4..c9c111198f4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -61,8 +61,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
@Before
public void setUp() throws Exception {
mPipAnimationController = new PipAnimationController(
- mContext, new PipSurfaceTransactionHelper(mContext,
- mock(ConfigurationController.class)));
+ new PipSurfaceTransactionHelper(mContext, mock(ConfigurationController.class)));
mLeash = new SurfaceControl.Builder()
.setContainerLayer()
.setName("FakeLeash")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
index f404f0489e01..70c2bba040a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java
@@ -270,6 +270,21 @@ public class PipBoundsHandlerTest extends SysuiTestCase {
}
@Test
+ public void onSaveReentryBounds_restoreLastSize() {
+ final Rect oldSize = mPipBoundsHandler.getDestinationBounds(mTestComponentName1,
+ DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+
+ oldSize.scale(1.25f);
+ mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, oldSize);
+
+ final Rect newSize = mPipBoundsHandler.getDestinationBounds(mTestComponentName1,
+ DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+
+ assertEquals(oldSize.width(), newSize.width());
+ assertEquals(oldSize.height(), newSize.height());
+ }
+
+ @Test
public void onResetReentryBounds_useDefaultBounds() {
final Rect defaultBounds = mPipBoundsHandler.getDestinationBounds(mTestComponentName1,
DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
@@ -299,6 +314,22 @@ public class PipBoundsHandlerTest extends SysuiTestCase {
assertBoundsInclusionWithMargin("restoreLastPosition", newBounds, actualBounds);
}
+ @Test
+ public void onSaveReentryBounds_componentMismatch_restoreLastSize() {
+ final Rect oldSize = mPipBoundsHandler.getDestinationBounds(mTestComponentName1,
+ DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+
+ oldSize.scale(1.25f);
+ mPipBoundsHandler.onSaveReentryBounds(mTestComponentName1, oldSize);
+
+ mPipBoundsHandler.onResetReentryBounds(mTestComponentName2);
+ final Rect newSize = mPipBoundsHandler.getDestinationBounds(mTestComponentName1,
+ DEFAULT_ASPECT_RATIO, EMPTY_CURRENT_BOUNDS, EMPTY_MINIMAL_SIZE);
+
+ assertEquals(oldSize.width(), newSize.width());
+ assertEquals(oldSize.height(), newSize.height());
+ }
+
private void assertBoundsInclusionWithMargin(String from, Rect expected, Rect actual) {
final Rect expectedWithMargin = new Rect(expected);
expectedWithMargin.inset(-ROUNDING_ERROR_MARGIN, -ROUNDING_ERROR_MARGIN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 438de99015a4..20f13bb02435 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -260,6 +260,14 @@ public class QSTileImplTest extends SysuiTestCase {
}
@Test
+ public void testHandleDestroyLifecycle() {
+ assertNotEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
+ mTile.handleDestroy();
+
+ assertEquals(DESTROYED, mTile.getLifecycle().getCurrentState());
+ }
+
+ @Test
public void testHandleDestroy_log() {
mTile.handleDestroy();
verify(mQsLogger).logTileDestroyed(eq(SPEC), anyString());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
index fa711f1cf9a2..a16fb5e8dc17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -23,10 +23,12 @@ import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
+import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Lifecycle.Event;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -76,6 +78,34 @@ public class CallbackControllerTest extends SysuiTestCase {
verify(controller).removeCallback(eq(callback));
}
+ @Test
+ public void testCallbackIsRemovedOnDestroy() {
+ SimpleLifecycleOwner owner = new SimpleLifecycleOwner();
+
+ Object callback = new Object();
+ Controller controller = mock(Controller.class);
+ controller.observe(owner, callback);
+
+ owner.setState(Lifecycle.State.RESUMED);
+ verify(controller).addCallback(callback);
+
+ owner.setState(Lifecycle.State.DESTROYED);
+ verify(controller).removeCallback(callback);
+ }
+
+ private static class SimpleLifecycleOwner implements LifecycleOwner {
+ LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+ @NonNull
+ @Override
+ public Lifecycle getLifecycle() {
+ return mLifecycle;
+ }
+
+ public void setState(Lifecycle.State state) {
+ mLifecycle.setCurrentState(state);
+ }
+ }
+
private static class Controller implements CallbackController<Object> {
@Override
public void addCallback(Object listener) {
diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
index 754584e70fad..6ddb122936e7 100644
--- a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
@@ -1,24 +1,6 @@
// Signature format: 2.0
package android.net {
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
public final class TetheringConstants {
field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
@@ -38,69 +20,15 @@ package android.net {
method @NonNull public String[] getTetheringErroredIfaces();
method public boolean isTetheringSupported();
method public boolean isTetheringSupported(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
method @Deprecated public int tether(@NonNull String);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
method @Deprecated public int untether(@NonNull String);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
}
public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
}
public static class TetheringManager.TetheringInterfaceRegexps {
@@ -109,21 +37,5 @@ package android.net {
method @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
}
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
index 48be0d96425c..645b00001330 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
@@ -16,8 +16,6 @@
package android.net;
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -36,7 +34,6 @@ import java.util.Objects;
* @hide
*/
@SystemApi
-@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public final class TetheredClient implements Parcelable {
@NonNull
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 7483bac11662..db8436859281 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -55,7 +55,6 @@ import java.util.function.Supplier;
* @hide
*/
@SystemApi
-@SystemApi(client = MODULE_LIBRARIES)
@TestApi
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
diff --git a/packages/Tethering/tests/privileged/Android.bp b/packages/Tethering/tests/privileged/Android.bp
new file mode 100644
index 000000000000..a0fb24603a93
--- /dev/null
+++ b/packages/Tethering/tests/privileged/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+ name: "TetheringPrivilegedTests",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ certificate: "networkstack",
+ platform_apis: true,
+ test_suites: [
+ "general-tests",
+ "mts",
+ ],
+ compile_multilib: "both",
+}
diff --git a/packages/Tethering/tests/privileged/AndroidManifest.xml b/packages/Tethering/tests/privileged/AndroidManifest.xml
new file mode 100644
index 000000000000..49eba15d13d4
--- /dev/null
+++ b/packages/Tethering/tests/privileged/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.networkstack.tethering.tests.privileged"
+ android:sharedUserId="android.uid.networkstack">
+
+ <!-- Note: do not add any privileged or signature permissions that are granted
+ to the network stack and its shared uid apps. Otherwise, the test APK will
+ install, but when the device is rebooted, it will bootloop because this
+ test APK is not in the privileged permission allow list -->
+
+ <application android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.networkstack.tethering.tests.privileged"
+ android:label="Tethering privileged tests">
+ </instrumentation>
+</manifest>
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index 14e6e91e3a25..a75fb2d47bbd 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -23,6 +23,8 @@
<permission android:name="com.android.smspush.WAPPUSH_MANAGER_BIND"
android:protectionLevel="signatureOrSystem" />
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+
<original-package android:name="com.android.smspush" />
<application
android:allowClearUserData="false">
diff --git a/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl b/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
index 4e54aba5c3bf..1bbc90d604f9 100644
--- a/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
+++ b/packages/services/PacProcessor/src/com/android/net/IProxyService.aidl
@@ -21,7 +21,4 @@ interface IProxyService
String resolvePacFile(String host, String url);
oneway void setPacFile(String scriptContents);
-
- oneway void startPacSystem();
- oneway void stopPacSystem();
}
diff --git a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
index 7aea721617b9..5a7de9f70b49 100644
--- a/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
+++ b/packages/services/PacProcessor/src/com/android/pacprocessor/PacService.java
@@ -88,15 +88,5 @@ public class PacService extends Service {
}
mLibpac.setCurrentProxyScript(script);
}
-
- @Override
- public void startPacSystem() throws RemoteException {
- //TODO: remove
- }
-
- @Override
- public void stopPacSystem() throws RemoteException {
- //TODO: remove
- }
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index dad061262d49..d50e9d720861 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -175,7 +175,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
*/
public FullScreenMagnificationGestureHandler(Context context,
FullScreenMagnificationController fullScreenMagnificationController,
- MagnificationGestureHandler.ScaleChangedListener listener,
+ ScaleChangedListener listener,
boolean detectTripleTap,
boolean detectShortcutTrigger,
int displayId) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
index f38c38ff7d26..d6f53d2c225c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureHandler.java
@@ -23,7 +23,7 @@ import com.android.server.accessibility.BaseEventStreamTransformation;
*/
public abstract class MagnificationGestureHandler extends BaseEventStreamTransformation {
- protected final MagnificationGestureHandler.ScaleChangedListener mListener;
+ protected final ScaleChangedListener mListener;
protected MagnificationGestureHandler(ScaleChangedListener listener) {
mListener = listener;
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
index 56c05199d0ca..bd25f2bea881 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java
@@ -100,7 +100,7 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl
*/
public WindowMagnificationGestureHandler(Context context,
WindowMagnificationManager windowMagnificationMgr,
- MagnificationGestureHandler.ScaleChangedListener listener, boolean detectTripleTap,
+ ScaleChangedListener listener, boolean detectTripleTap,
boolean detectShortcutTrigger, int displayId) {
super(listener);
if (DEBUG_ALL) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index a3c5d1edd351..a08c2dd4292d 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -17,7 +17,10 @@
package com.android.server.accessibility.magnification;
import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -52,17 +55,28 @@ public class WindowMagnificationManager implements
static final float MAX_SCALE = FullScreenMagnificationController.MAX_SCALE;
static final float MIN_SCALE = FullScreenMagnificationController.MIN_SCALE;
- private final Object mLock = new Object();;
+ private final Object mLock = new Object();
private final Context mContext;
@VisibleForTesting
@GuardedBy("mLock")
- @Nullable WindowMagnificationConnectionWrapper mConnectionWrapper;
+ @Nullable
+ WindowMagnificationConnectionWrapper mConnectionWrapper;
@GuardedBy("mLock")
private ConnectionCallback mConnectionCallback;
@GuardedBy("mLock")
private SparseArray<WindowMagnifier> mWindowMagnifiers = new SparseArray<>();
private int mUserId;
+ @VisibleForTesting
+ protected final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final int displayId = context.getDisplayId();
+ removeMagnificationButton(displayId);
+ disableWindowMagnification(displayId);
+ }
+ };
+
public WindowMagnificationManager(Context context, int userId) {
mContext = context;
mUserId = userId;
@@ -133,8 +147,12 @@ public class WindowMagnificationManager implements
if (connect == isConnected()) {
return false;
}
- if (!connect) {
+ if (connect) {
+ final IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+ mContext.registerReceiver(mScreenStateReceiver, intentFilter);
+ } else {
disableAllWindowMagnifiers();
+ mContext.unregisterReceiver(mScreenStateReceiver);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index 19248ca54611..c25dd37bc7d9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -31,9 +31,16 @@ import com.android.server.inputmethod.InputMethodManagerInternal;
import java.util.Optional;
import java.util.function.Consumer;
-
/**
- * Controls the interaction with the IME for the inline suggestion sessions.
+ * Controls the interaction with the IME for the {@link AutofillInlineSuggestionsRequestSession}s.
+ *
+ * <p>The class maintains the inline suggestion session with the autofill service. There is at most
+ * one active inline suggestion session at any given corresponding to one focused view.
+ * New sessions are created only when {@link #onCreateInlineSuggestionsRequestLocked} is called.</p>
+ *
+ * <p>The class manages the interaction between the {@link com.android.server.autofill.Session} and
+ * the inline suggestion session whenever inline suggestions can be provided. All calls to the
+ * inline suggestion session must be made through this controller.</p>
*/
final class AutofillInlineSessionController {
@NonNull
@@ -66,7 +73,6 @@ final class AutofillInlineSessionController {
mUiCallback = callback;
}
-
/**
* Requests the IME to create an {@link InlineSuggestionsRequest} for {@code autofillId}.
*
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index b2daae48bb0e..84fbe9a75a18 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -364,6 +364,9 @@ final class AutofillInlineSuggestionsRequestSession {
}
}
+ /**
+ * Internal implementation of {@link IInlineSuggestionsRequestCallback}.
+ */
private static final class InlineSuggestionsRequestCallbackImpl extends
IInlineSuggestionsRequestCallback.Stub {
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 2241569afe18..e80a6d9e0907 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -33,7 +33,7 @@ import android.os.ParcelFileDescriptor;
import android.util.Slog;
import com.android.server.LocalServices;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -134,10 +134,11 @@ public class PackageManagerBackupAgent extends BackupAgent {
init(packageMgr, packages, userId);
}
- public PackageManagerBackupAgent(PackageManager packageMgr, int userId) {
+ public PackageManagerBackupAgent(PackageManager packageMgr, int userId,
+ BackupEligibilityRules backupEligibilityRules) {
init(packageMgr, null, userId);
- evaluateStorablePackages();
+ evaluateStorablePackages(backupEligibilityRules);
}
private void init(PackageManager packageMgr, List<PackageInfo> packages, int userId) {
@@ -153,18 +154,19 @@ public class PackageManagerBackupAgent extends BackupAgent {
// We will need to refresh our understanding of what is eligible for
// backup periodically; this entry point serves that purpose.
- public void evaluateStorablePackages() {
- mAllPackages = getStorableApplications(mPackageManager, mUserId);
+ public void evaluateStorablePackages(BackupEligibilityRules backupEligibilityRules) {
+ mAllPackages = getStorableApplications(mPackageManager, mUserId, backupEligibilityRules);
}
/** Gets all packages installed on user {@code userId} eligible for backup. */
- public static List<PackageInfo> getStorableApplications(PackageManager pm, int userId) {
+ public static List<PackageInfo> getStorableApplications(PackageManager pm, int userId,
+ BackupEligibilityRules backupEligibilityRules) {
List<PackageInfo> pkgs =
pm.getInstalledPackagesAsUser(PackageManager.GET_SIGNING_CERTIFICATES, userId);
int N = pkgs.size();
for (int a = N-1; a >= 0; a--) {
PackageInfo pkg = pkgs.get(a);
- if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo, userId)) {
+ if (!backupEligibilityRules.appIsEligibleForBackup(pkg.applicationInfo)) {
pkgs.remove(a);
}
}
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index d6a075f18141..ff21a733223c 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -68,6 +68,7 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
@@ -127,7 +128,7 @@ import com.android.server.backup.restore.ActiveRestoreSession;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportNotRegisteredException;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
@@ -336,6 +337,7 @@ public class UserBackupManagerService {
private final BackupManagerConstants mConstants;
private final BackupWakeLock mWakelock;
private final BackupHandler mBackupHandler;
+ private final BackupEligibilityRules mScheduledBackupEligibility;
private final IBackupManager mBackupManagerBinder;
@@ -563,6 +565,7 @@ public class UserBackupManagerService {
mActivityManager = null;
mStorageManager = null;
mBackupManagerBinder = null;
+ mScheduledBackupEligibility = null;
}
private UserBackupManagerService(
@@ -579,6 +582,8 @@ public class UserBackupManagerService {
mPackageManagerBinder = AppGlobals.getPackageManager();
mActivityManager = ActivityManager.getService();
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mScheduledBackupEligibility = getEligibilityRules(mPackageManager, userId,
+ OperationType.BACKUP);
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -914,7 +919,13 @@ public class UserBackupManagerService {
* non-lifecycle agent instance, so we manually set up the context topology for it.
*/
public BackupAgent makeMetadataAgent() {
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId);
+ return makeMetadataAgentWithEligibilityRules(mScheduledBackupEligibility);
+ }
+
+ public BackupAgent makeMetadataAgentWithEligibilityRules(
+ BackupEligibilityRules backupEligibilityRules) {
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId,
+ backupEligibilityRules);
pmAgent.attach(mContext);
pmAgent.onCreate(UserHandle.of(mUserId));
return pmAgent;
@@ -996,7 +1007,8 @@ public class UserBackupManagerService {
boolean changed = false;
ArrayList<FullBackupEntry> schedule = null;
List<PackageInfo> apps =
- PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId);
+ PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId,
+ mScheduledBackupEligibility);
if (mFullBackupScheduleFile.exists()) {
try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
@@ -1026,9 +1038,9 @@ public class UserBackupManagerService {
foundApps.add(pkgName); // all apps that we've addressed already
try {
PackageInfo pkg = mPackageManager.getPackageInfoAsUser(pkgName, 0, mUserId);
- if (AppBackupUtils.appGetsFullBackup(pkg)
- && AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo,
- mUserId)) {
+ if (mScheduledBackupEligibility.appGetsFullBackup(pkg)
+ && mScheduledBackupEligibility.appIsEligibleForBackup(
+ pkg.applicationInfo)) {
schedule.add(new FullBackupEntry(pkgName, lastBackup));
} else {
if (DEBUG) {
@@ -1047,9 +1059,9 @@ public class UserBackupManagerService {
// New apps can arrive "out of band" via OTA and similar, so we also need to
// scan to make sure that we're tracking all full-backup candidates properly
for (PackageInfo app : apps) {
- if (AppBackupUtils.appGetsFullBackup(app)
- && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo,
- mUserId)) {
+ if (mScheduledBackupEligibility.appGetsFullBackup(app)
+ && mScheduledBackupEligibility.appIsEligibleForBackup(
+ app.applicationInfo)) {
if (!foundApps.contains(app.packageName)) {
if (MORE_DEBUG) {
Slog.i(
@@ -1080,8 +1092,9 @@ public class UserBackupManagerService {
changed = true;
schedule = new ArrayList<>(apps.size());
for (PackageInfo info : apps) {
- if (AppBackupUtils.appGetsFullBackup(info) && AppBackupUtils.appIsEligibleForBackup(
- info.applicationInfo, mUserId)) {
+ if (mScheduledBackupEligibility.appGetsFullBackup(info)
+ && mScheduledBackupEligibility.appIsEligibleForBackup(
+ info.applicationInfo)) {
schedule.add(new FullBackupEntry(info.packageName, 0));
}
}
@@ -1381,9 +1394,9 @@ public class UserBackupManagerService {
PackageInfo app =
mPackageManager.getPackageInfoAsUser(
packageName, /* flags */ 0, mUserId);
- if (AppBackupUtils.appGetsFullBackup(app)
- && AppBackupUtils.appIsEligibleForBackup(
- app.applicationInfo, mUserId)) {
+ if (mScheduledBackupEligibility.appGetsFullBackup(app)
+ && mScheduledBackupEligibility.appIsEligibleForBackup(
+ app.applicationInfo)) {
enqueueFullBackup(packageName, now);
scheduleNextFullBackupJob(0);
} else {
@@ -1881,9 +1894,11 @@ public class UserBackupManagerService {
OnTaskFinishedListener listener =
caller -> mTransportManager.disposeOfTransportClient(transportClient, caller);
+ BackupEligibilityRules backupEligibilityRules = getEligibilityRulesForOperation(
+ operationType);
Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
- msg.obj = getRequestBackupParams(packages, observer, monitor, flags, operationType,
+ msg.obj = getRequestBackupParams(packages, observer, monitor, flags, backupEligibilityRules,
transportClient, transportDirName, listener);
mBackupHandler.sendMessage(msg);
return BackupManager.SUCCESS;
@@ -1891,7 +1906,7 @@ public class UserBackupManagerService {
@VisibleForTesting
BackupParams getRequestBackupParams(String[] packages, IBackupObserver observer,
- IBackupManagerMonitor monitor, int flags, @OperationType int operationType,
+ IBackupManagerMonitor monitor, int flags, BackupEligibilityRules backupEligibilityRules,
TransportClient transportClient, String transportDirName,
OnTaskFinishedListener listener) {
ArrayList<String> fullBackupList = new ArrayList<>();
@@ -1904,13 +1919,12 @@ public class UserBackupManagerService {
try {
PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
- if (!appIsEligibleForBackup(packageInfo.applicationInfo, mUserId,
- operationType)) {
+ if (!backupEligibilityRules.appIsEligibleForBackup(packageInfo.applicationInfo)) {
BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
}
- if (appGetsFullBackup(packageInfo, operationType)) {
+ if (backupEligibilityRules.appGetsFullBackup(packageInfo)) {
fullBackupList.add(packageInfo.packageName);
} else {
kvBackupList.add(packageInfo.packageName);
@@ -1941,18 +1955,7 @@ public class UserBackupManagerService {
return new BackupParams(transportClient, transportDirName, kvBackupList, fullBackupList,
observer, monitor, listener, /* userInitiated */ true, nonIncrementalBackup,
- operationType);
- }
-
- @VisibleForTesting
- boolean appIsEligibleForBackup(ApplicationInfo applicationInfo, int userId,
- @OperationType int operationType) {
- return AppBackupUtils.appIsEligibleForBackup(applicationInfo, userId, operationType);
- }
-
- @VisibleForTesting
- boolean appGetsFullBackup(PackageInfo packageInfo, @OperationType int operationType) {
- return AppBackupUtils.appGetsFullBackup(packageInfo, operationType);
+ backupEligibilityRules);
}
/** Cancel all running backups. */
@@ -2481,7 +2484,7 @@ public class UserBackupManagerService {
try {
PackageInfo appInfo = mPackageManager.getPackageInfoAsUser(
entry.packageName, 0, mUserId);
- if (!AppBackupUtils.appGetsFullBackup(appInfo)) {
+ if (!mScheduledBackupEligibility.appGetsFullBackup(appInfo)) {
// The head app isn't supposed to get full-data backups [any more];
// so we cull it and force a loop around to consider the new head
// app.
@@ -2562,7 +2565,8 @@ public class UserBackupManagerService {
/* backupObserver */ null,
/* monitor */ null,
/* userInitiated */ false,
- "BMS.beginFullBackup()");
+ "BMS.beginFullBackup()",
+ getEligibilityRulesForOperation(OperationType.BACKUP));
// Acquiring wakelock for PerformFullTransportBackupTask before its start.
mWakelock.acquire();
(new Thread(mRunningFullBackupTask)).start();
@@ -3001,7 +3005,7 @@ public class UserBackupManagerService {
AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
- pkgList);
+ pkgList, mScheduledBackupEligibility);
final int token = generateRandomIntegerToken();
synchronized (mAdbBackupRestoreConfirmations) {
mAdbBackupRestoreConfirmations.put(token, params);
@@ -3086,7 +3090,8 @@ public class UserBackupManagerService {
/* backupObserver */ null,
/* monitor */ null,
/* userInitiated */ false,
- "BMS.fullTransportBackup()");
+ "BMS.fullTransportBackup()",
+ getEligibilityRulesForOperation(OperationType.BACKUP));
// Acquiring wakelock for PerformFullTransportBackupTask before its start.
mWakelock.acquire();
(new Thread(task, "full-transport-master")).start();
@@ -4137,8 +4142,8 @@ public class UserBackupManagerService {
TransportClient transportClient =
mTransportManager.getCurrentTransportClient(callerLogString);
boolean eligible =
- AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager, mUserId);
+ mScheduledBackupEligibility.appIsRunningAndEligibleForBackupWithTransport(
+ transportClient, packageName);
if (transportClient != null) {
mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
}
@@ -4160,9 +4165,8 @@ public class UserBackupManagerService {
mTransportManager.getCurrentTransportClient(callerLogString);
List<String> eligibleApps = new LinkedList<>();
for (String packageName : packages) {
- if (AppBackupUtils
- .appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager, mUserId)) {
+ if (mScheduledBackupEligibility.appIsRunningAndEligibleForBackupWithTransport(
+ transportClient, packageName)) {
eligibleApps.add(packageName);
}
}
@@ -4175,6 +4179,17 @@ public class UserBackupManagerService {
}
}
+ public BackupEligibilityRules getEligibilityRulesForOperation(
+ @OperationType int operationType) {
+ return getEligibilityRules(mPackageManager, mUserId, operationType);
+ }
+
+ private static BackupEligibilityRules getEligibilityRules(PackageManager packageManager,
+ int userId, @OperationType int operationType) {
+ return new BackupEligibilityRules(packageManager,
+ LocalServices.getService(PackageManagerInternal.class), userId, operationType);
+ }
+
/** Prints service state for 'dumpsys backup'. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
long identityToken = Binder.clearCallingIdentity();
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 0a7159bfe1b7..a69bd6b62264 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -24,6 +24,8 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEA
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupManager.OperationType;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -38,7 +40,7 @@ import com.android.server.AppWidgetBackupBridge;
import com.android.server.backup.BackupRestoreTask;
import com.android.server.backup.KeyValueAdbBackupEngine;
import com.android.server.backup.UserBackupManagerService;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.PasswordUtils;
import java.io.ByteArrayOutputStream;
@@ -83,12 +85,14 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
private final String mCurrentPassword;
private final String mEncryptPassword;
private final int mCurrentOpToken;
+ private final BackupEligibilityRules mBackupEligibilityRules;
public PerformAdbBackupTask(UserBackupManagerService backupManagerService,
ParcelFileDescriptor fd, IFullBackupRestoreObserver observer,
boolean includeApks, boolean includeObbs, boolean includeShared, boolean doWidgets,
String curPassword, String encryptPassword, boolean doAllApps, boolean doSystem,
- boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch) {
+ boolean doCompress, boolean doKeyValue, String[] packages, AtomicBoolean latch,
+ BackupEligibilityRules backupEligibilityRules) {
super(observer);
mUserBackupManagerService = backupManagerService;
mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
@@ -119,6 +123,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
}
mCompress = doCompress;
mKeyValue = doKeyValue;
+ mBackupEligibilityRules = backupEligibilityRules;
}
private void addPackagesToSet(TreeMap<String, PackageInfo> set, List<String> pkgNames) {
@@ -286,15 +291,14 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
while (iter.hasNext()) {
PackageInfo pkg = iter.next().getValue();
- if (!AppBackupUtils.appIsEligibleForBackup(pkg.applicationInfo,
- mUserBackupManagerService.getUserId())
- || AppBackupUtils.appIsStopped(pkg.applicationInfo)) {
+ if (!mBackupEligibilityRules.appIsEligibleForBackup(pkg.applicationInfo)
+ || mBackupEligibilityRules.appIsStopped(pkg.applicationInfo)) {
iter.remove();
if (DEBUG) {
Slog.i(TAG, "Package " + pkg.packageName
+ " is not eligible for backup, removing.");
}
- } else if (AppBackupUtils.appIsKeyValueOnly(pkg)) {
+ } else if (mBackupEligibilityRules.appIsKeyValueOnly(pkg)) {
iter.remove();
if (DEBUG) {
Slog.i(TAG, "Package " + pkg.packageName
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 738dd9bf0f0d..1fa88920ca74 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -53,7 +53,7 @@ import com.android.server.backup.internal.Operation;
import com.android.server.backup.remote.RemoteCall;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportNotAvailableException;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
@@ -107,7 +107,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
IBackupObserver backupObserver,
IBackupManagerMonitor monitor,
boolean userInitiated,
- String caller) {
+ String caller,
+ BackupEligibilityRules backupEligibilityRules) {
TransportManager transportManager = backupManagerService.getTransportManager();
TransportClient transportClient = transportManager.getCurrentTransportClient(caller);
OnTaskFinishedListener listener =
@@ -124,7 +125,8 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
backupObserver,
monitor,
listener,
- userInitiated);
+ userInitiated,
+ backupEligibilityRules);
}
private static final String TAG = "PFTBT";
@@ -151,6 +153,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
private volatile boolean mCancelAll;
private final int mCurrentOpToken;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
+ private final BackupEligibilityRules mBackupEligibilityRules;
public PerformFullTransportBackupTask(UserBackupManagerService backupManagerService,
TransportClient transportClient,
@@ -158,7 +161,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
String[] whichPackages, boolean updateSchedule,
FullBackupJob runningJob, CountDownLatch latch, IBackupObserver backupObserver,
@Nullable IBackupManagerMonitor monitor, @Nullable OnTaskFinishedListener listener,
- boolean userInitiated) {
+ boolean userInitiated, BackupEligibilityRules backupEligibilityRules) {
super(observer);
this.mUserBackupManagerService = backupManagerService;
mTransportClient = transportClient;
@@ -176,6 +179,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
mUserId = backupManagerService.getUserId();
+ mBackupEligibilityRules = backupEligibilityRules;
if (backupManagerService.isBackupOperationInProgress()) {
if (DEBUG) {
@@ -193,7 +197,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
PackageInfo info = pm.getPackageInfoAsUser(pkg,
PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
mCurrentPackage = info;
- if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, mUserId)) {
+ if (!mBackupEligibilityRules.appIsEligibleForBackup(info.applicationInfo)) {
// Cull any packages that have indicated that backups are not permitted,
// that run as system-domain uids but do not define their own backup agents,
// as well as any explicit mention of the 'special' shared-storage agent
@@ -209,7 +213,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
- } else if (!AppBackupUtils.appGetsFullBackup(info)) {
+ } else if (!mBackupEligibilityRules.appGetsFullBackup(info)) {
// Cull any packages that are found in the queue but now aren't supposed
// to get full-data backup operations.
if (MORE_DEBUG) {
@@ -224,7 +228,7 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
BackupObserverUtils.sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
- } else if (AppBackupUtils.appIsStopped(info.applicationInfo)) {
+ } else if (mBackupEligibilityRules.appIsStopped(info.applicationInfo)) {
// Cull any packages in the 'stopped' state: they've either just been
// installed or have explicitly been force-stopped by the user. In both
// cases we do not want to launch them for backup.
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 87a8e4982529..1bb434950563 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -20,6 +20,8 @@ import static com.android.server.backup.BackupManagerService.DEBUG;
import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
import static com.android.server.backup.BackupManagerService.TAG;
+import android.app.backup.BackupManager;
+import android.app.backup.BackupManager.OperationType;
import android.app.backup.RestoreSet;
import android.os.Handler;
import android.os.HandlerThread;
@@ -222,7 +224,9 @@ public class BackupHandler extends Handler {
listener,
Collections.emptyList(),
/* userInitiated */ false,
- /* nonIncremental */ false);
+ /* nonIncremental */ false,
+ backupManagerService.getEligibilityRulesForOperation(
+ OperationType.BACKUP));
} catch (Exception e) {
// unable to ask the transport its dir name -- transient failure, since
// the above check succeeded. Try again next time.
@@ -279,7 +283,8 @@ public class BackupHandler extends Handler {
params.observer, params.includeApks, params.includeObbs,
params.includeShared, params.doWidgets, params.curPassword,
params.encryptPassword, params.allApps, params.includeSystem,
- params.doCompress, params.includeKeyValue, params.packages, params.latch);
+ params.doCompress, params.includeKeyValue, params.packages, params.latch,
+ params.backupEligibilityRules);
(new Thread(task, "adb-backup")).start();
break;
}
@@ -299,7 +304,9 @@ public class BackupHandler extends Handler {
params.pmToken,
params.isSystemRestore,
params.filterSet,
- params.listener);
+ params.listener,
+ backupManagerService.getEligibilityRulesForOperation(
+ OperationType.BACKUP));
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.isRestoreInProgress()) {
@@ -462,7 +469,8 @@ public class BackupHandler extends Handler {
params.listener,
params.fullPackages,
/* userInitiated */ true,
- params.nonIncrementalBackup);
+ params.nonIncrementalBackup,
+ params.mBackupEligibilityRules);
break;
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index f146e491c488..6124171c7a0e 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -67,7 +67,7 @@ import com.android.server.backup.remote.RemoteCallable;
import com.android.server.backup.remote.RemoteResult;
import com.android.server.backup.transport.TransportClient;
import com.android.server.backup.transport.TransportNotAvailableException;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import libcore.io.IoUtils;
@@ -220,7 +220,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
OnTaskFinishedListener listener,
List<String> pendingFullBackups,
boolean userInitiated,
- boolean nonIncremental) {
+ boolean nonIncremental,
+ BackupEligibilityRules backupEligibilityRules) {
KeyValueBackupReporter reporter =
new KeyValueBackupReporter(backupManagerService, observer, monitor);
KeyValueBackupTask task =
@@ -234,7 +235,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
listener,
pendingFullBackups,
userInitiated,
- nonIncremental);
+ nonIncremental,
+ backupEligibilityRules);
Thread thread = new Thread(task, "key-value-backup-" + THREAD_COUNT.incrementAndGet());
thread.start();
KeyValueBackupReporter.onNewThread(thread.getName());
@@ -258,6 +260,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
private final List<String> mPendingFullBackups;
private final Object mQueueLock;
@Nullable private final DataChangedJournal mJournal;
+ private final BackupEligibilityRules mBackupEligibilityRules;
@Nullable private PerformFullTransportBackupTask mFullBackupTask;
@Nullable private IBackupAgent mAgent;
@@ -307,7 +310,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
OnTaskFinishedListener taskFinishedListener,
List<String> pendingFullBackups,
boolean userInitiated,
- boolean nonIncremental) {
+ boolean nonIncremental,
+ BackupEligibilityRules backupEligibilityRules) {
mBackupManagerService = backupManagerService;
mPackageManager = backupManagerService.getPackageManager();
mTransportClient = transportClient;
@@ -330,6 +334,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
mQueueLock = mBackupManagerService.getQueueLock();
mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
mUserId = backupManagerService.getUserId();
+ mBackupEligibilityRules = backupEligibilityRules;
}
private void registerTask() {
@@ -456,9 +461,9 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
/** Determine if a package is eligible to be backed up to the transport */
private boolean isEligibleForNoDataCall(PackageInfo packageInfo) {
- return AppBackupUtils.appIsKeyValueOnly(packageInfo)
- && AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(mTransportClient,
- packageInfo.packageName, mPackageManager, mUserId);
+ return mBackupEligibilityRules.appIsKeyValueOnly(packageInfo)
+ && mBackupEligibilityRules.appIsRunningAndEligibleForBackupWithTransport(
+ mTransportClient, packageInfo.packageName);
}
/** Send the "no data changed" message to a transport for a specific package */
@@ -642,7 +647,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
mReporter.getObserver(),
mReporter.getMonitor(),
mTaskFinishedListener,
- mUserInitiated);
+ mUserInitiated,
+ mBackupEligibilityRules);
}
private void backupPm() throws TaskException {
@@ -704,15 +710,15 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
throw AgentException.permanent(e);
}
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
- if (!AppBackupUtils.appIsEligibleForBackup(applicationInfo, mUserId)) {
+ if (!mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo)) {
mReporter.onPackageNotEligibleForBackup(packageName);
throw AgentException.permanent();
}
- if (AppBackupUtils.appGetsFullBackup(packageInfo)) {
+ if (mBackupEligibilityRules.appGetsFullBackup(packageInfo)) {
mReporter.onPackageEligibleForFullBackup(packageName);
throw AgentException.permanent();
}
- if (AppBackupUtils.appIsStopped(applicationInfo)) {
+ if (mBackupEligibilityRules.appIsStopped(applicationInfo)) {
mReporter.onPackageStopped(packageName);
throw AgentException.permanent();
}
@@ -843,7 +849,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
/** Same as {@link #extractAgentData(PackageInfo)}, but only for PM package. */
private void extractPmAgentData(PackageInfo packageInfo) throws AgentException, TaskException {
Preconditions.checkArgument(packageInfo.packageName.equals(PM_PACKAGE));
- BackupAgent pmAgent = mBackupManagerService.makeMetadataAgent();
+ BackupAgent pmAgent = mBackupManagerService.makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
mAgent = IBackupAgent.Stub.asInterface(pmAgent.onBind());
extractAgentData(packageInfo, mAgent);
}
diff --git a/services/backup/java/com/android/server/backup/params/AdbBackupParams.java b/services/backup/java/com/android/server/backup/params/AdbBackupParams.java
index 5c1ba24ffbc2..f08c5fa3919b 100644
--- a/services/backup/java/com/android/server/backup/params/AdbBackupParams.java
+++ b/services/backup/java/com/android/server/backup/params/AdbBackupParams.java
@@ -18,6 +18,8 @@ package com.android.server.backup.params;
import android.os.ParcelFileDescriptor;
+import com.android.server.backup.utils.BackupEligibilityRules;
+
public class AdbBackupParams extends AdbParams {
public boolean includeApks;
@@ -29,10 +31,12 @@ public class AdbBackupParams extends AdbParams {
public boolean doCompress;
public boolean includeKeyValue;
public String[] packages;
+ public BackupEligibilityRules backupEligibilityRules;
public AdbBackupParams(ParcelFileDescriptor output, boolean saveApks, boolean saveObbs,
boolean saveShared, boolean alsoWidgets, boolean doAllApps, boolean doSystem,
- boolean compress, boolean doKeyValue, String[] pkgList) {
+ boolean compress, boolean doKeyValue, String[] pkgList,
+ BackupEligibilityRules eligibilityRules) {
fd = output;
includeApks = saveApks;
includeObbs = saveObbs;
@@ -43,5 +47,6 @@ public class AdbBackupParams extends AdbParams {
doCompress = compress;
includeKeyValue = doKeyValue;
packages = pkgList;
+ backupEligibilityRules = eligibilityRules;
}
}
diff --git a/services/backup/java/com/android/server/backup/params/BackupParams.java b/services/backup/java/com/android/server/backup/params/BackupParams.java
index 514434ec9d39..800257002f01 100644
--- a/services/backup/java/com/android/server/backup/params/BackupParams.java
+++ b/services/backup/java/com/android/server/backup/params/BackupParams.java
@@ -16,12 +16,12 @@
package com.android.server.backup.params;
-import android.app.backup.BackupManager.OperationType;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IBackupObserver;
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import java.util.ArrayList;
@@ -36,12 +36,12 @@ public class BackupParams {
public OnTaskFinishedListener listener;
public boolean userInitiated;
public boolean nonIncrementalBackup;
- @OperationType public int operationType;
+ public BackupEligibilityRules mBackupEligibilityRules;
public BackupParams(TransportClient transportClient, String dirName,
ArrayList<String> kvPackages, ArrayList<String> fullPackages, IBackupObserver observer,
IBackupManagerMonitor monitor, OnTaskFinishedListener listener, boolean userInitiated,
- boolean nonIncrementalBackup, int operationType) {
+ boolean nonIncrementalBackup, BackupEligibilityRules backupEligibilityRules) {
this.transportClient = transportClient;
this.dirName = dirName;
this.kvPackages = kvPackages;
@@ -51,6 +51,6 @@ public class BackupParams {
this.listener = listener;
this.userInitiated = userInitiated;
this.nonIncrementalBackup = nonIncrementalBackup;
- this.operationType = operationType;
+ this.mBackupEligibilityRules = backupEligibilityRules;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 12113fea12a4..a7e360403ccc 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -66,7 +66,7 @@ import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.transport.TransportClient;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import libcore.io.IoUtils;
@@ -186,7 +186,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
int pmToken,
boolean isFullSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
this.backupManagerService = backupManagerService;
mUserId = backupManagerService.getUserId();
mTransportManager = backupManagerService.getTransportManager();
@@ -218,7 +219,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// We want everything and a pony
List<PackageInfo> apps =
PackageManagerBackupAgent.getStorableApplications(
- backupManagerService.getPackageManager(), mUserId);
+ backupManagerService.getPackageManager(), mUserId,
+ backupEligibilityRules);
filterSet = packagesToNames(apps);
if (DEBUG) {
Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps");
@@ -245,7 +247,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
continue;
}
- if (AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, mUserId)) {
+ if (backupEligibilityRules.appIsEligibleForBackup(info.applicationInfo)) {
mAcceptSet.add(info);
}
} catch (NameNotFoundException e) {
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index a616e0e9a1c6..162921528e95 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -47,12 +47,34 @@ import java.util.Set;
/**
* Utility methods wrapping operations on ApplicationInfo and PackageInfo.
*/
-public class AppBackupUtils {
+public class BackupEligibilityRules {
private static final boolean DEBUG = false;
// Whitelist of system packages that are eligible for backup in non-system users.
private static final Set<String> systemPackagesWhitelistedForAllUsers =
Sets.newArraySet(PACKAGE_MANAGER_SENTINEL, PLATFORM_PACKAGE_NAME);
+ private final PackageManager mPackageManager;
+ private final PackageManagerInternal mPackageManagerInternal;
+ private final int mUserId;
+ @OperationType private final int mOperationType;
+
+ public static BackupEligibilityRules forBackup(PackageManager packageManager,
+ PackageManagerInternal packageManagerInternal,
+ int userId) {
+ return new BackupEligibilityRules(packageManager, packageManagerInternal, userId,
+ OperationType.BACKUP);
+ }
+
+ public BackupEligibilityRules(PackageManager packageManager,
+ PackageManagerInternal packageManagerInternal,
+ int userId,
+ @OperationType int operationType) {
+ mPackageManager = packageManager;
+ mPackageManagerInternal = packageManagerInternal;
+ mUserId = userId;
+ mOperationType = operationType;
+ }
+
/**
* Returns whether app is eligible for backup.
*
@@ -65,32 +87,18 @@ public class AppBackupUtils {
* <li>it is the special shared-storage backup package used for 'adb backup'
* </ol>
*/
- public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) {
- return appIsEligibleForBackup(
- app, LocalServices.getService(PackageManagerInternal.class), userId,
- OperationType.BACKUP);
- }
-
- public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId,
- @OperationType int operationType) {
- return appIsEligibleForBackup(
- app, LocalServices.getService(PackageManagerInternal.class), userId, operationType);
- }
-
@VisibleForTesting
- static boolean appIsEligibleForBackup(
- ApplicationInfo app, PackageManagerInternal packageManager, int userId,
- @OperationType int operationType) {
+ public boolean appIsEligibleForBackup(ApplicationInfo app) {
// 1. their manifest states android:allowBackup="false"
boolean appAllowsBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
- if (!appAllowsBackup && !forceFullBackup(app.uid, operationType)) {
+ if (!appAllowsBackup && !forceFullBackup(app.uid, mOperationType)) {
return false;
}
// 2. they run as a system-level uid
if (UserHandle.isCore(app.uid)) {
// and the backup is happening for non-system user on a non-whitelisted package.
- if (userId != UserHandle.USER_SYSTEM
+ if (mUserId != UserHandle.USER_SYSTEM
&& !systemPackagesWhitelistedForAllUsers.contains(app.packageName)) {
return false;
}
@@ -111,7 +119,7 @@ public class AppBackupUtils {
return false;
}
- return !appIsDisabled(app, packageManager, userId);
+ return !appIsDisabled(app);
}
/**
@@ -124,18 +132,16 @@ public class AppBackupUtils {
* {@link BackupTransport#isAppEligibleForBackup(PackageInfo, boolean)}
* </ol>
*/
- public static boolean appIsRunningAndEligibleForBackupWithTransport(
+ public boolean appIsRunningAndEligibleForBackupWithTransport(
@Nullable TransportClient transportClient,
- String packageName,
- PackageManager pm,
- int userId) {
+ String packageName) {
try {
- PackageInfo packageInfo = pm.getPackageInfoAsUser(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES, userId);
+ PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
- if (!appIsEligibleForBackup(applicationInfo, userId)
+ if (!appIsEligibleForBackup(applicationInfo)
|| appIsStopped(applicationInfo)
- || appIsDisabled(applicationInfo, userId)) {
+ || appIsDisabled(applicationInfo)) {
return false;
}
if (transportClient != null) {
@@ -144,7 +150,7 @@ public class AppBackupUtils {
transportClient.connectOrThrow(
"AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport");
return transport.isAppEligibleForBackup(
- packageInfo, AppBackupUtils.appGetsFullBackup(packageInfo));
+ packageInfo, appGetsFullBackup(packageInfo));
} catch (Exception e) {
Slog.e(TAG, "Unable to ask about eligibility: " + e.getMessage());
}
@@ -157,14 +163,11 @@ public class AppBackupUtils {
}
/** Avoid backups of 'disabled' apps. */
- static boolean appIsDisabled(ApplicationInfo app, int userId) {
- return appIsDisabled(app, LocalServices.getService(PackageManagerInternal.class), userId);
- }
-
@VisibleForTesting
- static boolean appIsDisabled(
- ApplicationInfo app, PackageManagerInternal packageManager, int userId) {
- int enabledSetting = packageManager.getApplicationEnabledState(app.packageName, userId);
+ boolean appIsDisabled(
+ ApplicationInfo app) {
+ int enabledSetting = mPackageManagerInternal.getApplicationEnabledState(app.packageName,
+ mUserId);
switch (enabledSetting) {
case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
@@ -190,7 +193,7 @@ public class AppBackupUtils {
* <li>The app has just been installed.
* </ul>
*/
- public static boolean appIsStopped(ApplicationInfo app) {
+ public boolean appIsStopped(ApplicationInfo app) {
return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
}
@@ -198,13 +201,9 @@ public class AppBackupUtils {
* Returns whether the app can get full backup. Does *not* check overall backup eligibility
* policy!
*/
- public static boolean appGetsFullBackup(PackageInfo pkg) {
- return appGetsFullBackup(pkg, OperationType.BACKUP);
- }
-
@VisibleForTesting
- public static boolean appGetsFullBackup(PackageInfo pkg, @OperationType int operationType) {
- if (forceFullBackup(pkg.applicationInfo.uid, operationType)) {
+ public boolean appGetsFullBackup(PackageInfo pkg) {
+ if (forceFullBackup(pkg.applicationInfo.uid, mOperationType)) {
// If this is a migration, all non-system packages get full backup.
return true;
}
@@ -218,12 +217,11 @@ public class AppBackupUtils {
return true;
}
- public static boolean appIgnoresIncludeExcludeRules(ApplicationInfo app,
- @OperationType int operationType) {
- return forceFullBackup(app.uid, operationType);
+ public boolean appIgnoresIncludeExcludeRules(ApplicationInfo app) {
+ return forceFullBackup(app.uid, mOperationType);
}
- private static boolean forceFullBackup(int appUid, @OperationType int operationType) {
+ private boolean forceFullBackup(int appUid, @OperationType int operationType) {
return operationType == OperationType.MIGRATION &&
!UserHandle.isCore(appUid);
}
@@ -232,7 +230,7 @@ public class AppBackupUtils {
* Returns whether the app is only capable of doing key/value. We say it's not if it allows full
* backup, and it is otherwise.
*/
- public static boolean appIsKeyValueOnly(PackageInfo pkg) {
+ public boolean appIsKeyValueOnly(PackageInfo pkg) {
return !appGetsFullBackup(pkg);
}
@@ -254,8 +252,7 @@ public class AppBackupUtils {
*
* Note that if {@param target} is null we return false.
*/
- public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target,
- PackageManagerInternal pmi) {
+ public boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
if (target == null || target.packageName == null) {
return false;
}
@@ -296,7 +293,7 @@ public class AppBackupUtils {
// TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
// restoring from higher version to lower after having rotated the key (i.e. higher
// version has different sig than lower version that we want to restore to)
- return pmi.isDataRestoreSafe(storedSigs[0], target.packageName);
+ return mPackageManagerInternal.isDataRestoreSafe(storedSigs[0], target.packageName);
} else {
// the app couldn't have rotated keys, since it was signed with multiple sigs - do
// a check to see if we find a match for all stored sigs
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index 97bde9c03440..8e8bac435503 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -159,7 +159,9 @@ public class RestoreUtils {
Signature[] sigs = manifestSignatures.get(info.packageName);
PackageManagerInternal pmi = LocalServices.getService(
PackageManagerInternal.class);
- if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) {
+ BackupEligibilityRules eligibilityRules =
+ BackupEligibilityRules.forBackup(packageManager, pmi, userId);
+ if (eligibilityRules.signaturesMatch(sigs, pkg)) {
// If this is a system-uid app without a declared backup agent,
// don't restore any of the file data.
if (UserHandle.isCore(pkg.applicationInfo.uid)
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index d2d382dfc14d..bf8e9c8512ae 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -394,7 +394,8 @@ public class TarBackupReader {
}
RestorePolicy policy = RestorePolicy.IGNORE;
-
+ BackupEligibilityRules eligibilityRules = BackupEligibilityRules.forBackup(packageManager,
+ pmi, userId);
// Okay, got the manifest info we need...
try {
PackageInfo pkgInfo = packageManager.getPackageInfoAsUser(
@@ -413,7 +414,7 @@ public class TarBackupReader {
// such packages are signed with the platform cert instead of
// the app developer's cert, so they're different on every
// device.
- if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) {
+ if (eligibilityRules.signaturesMatch(signatures, pkgInfo)) {
if ((pkgInfo.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
Slog.i(TAG, "Package has restoreAnyVersion; taking data");
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 028d41234dd0..886bfb8f4736 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -159,7 +160,14 @@ public final class DropBoxManagerService extends SystemService {
@Override
public DropBoxManager.Entry getNextEntry(String tag, long millis, String callingPackage) {
- return DropBoxManagerService.this.getNextEntry(tag, millis, callingPackage);
+ return getNextEntryWithAttribution(tag, millis, callingPackage, null);
+ }
+
+ @Override
+ public DropBoxManager.Entry getNextEntryWithAttribution(String tag, long millis,
+ String callingPackage, String callingAttributionTag) {
+ return DropBoxManagerService.this.getNextEntry(tag, millis, callingPackage,
+ callingAttributionTag);
}
@Override
@@ -470,7 +478,8 @@ public final class DropBoxManagerService extends SystemService {
}
}
- private boolean checkPermission(int callingUid, String callingPackage) {
+ private boolean checkPermission(int callingUid, String callingPackage,
+ @Nullable String callingAttributionTag) {
// If callers have this permission, then we don't need to check
// USAGE_STATS, because they are part of the system and have agreed to
// check USAGE_STATS before passing the data along.
@@ -484,8 +493,9 @@ public final class DropBoxManagerService extends SystemService {
android.Manifest.permission.READ_LOGS, TAG);
// Callers also need the ability to read usage statistics
- switch (getContext().getSystemService(AppOpsManager.class)
- .noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage)) {
+ switch (getContext().getSystemService(AppOpsManager.class).noteOp(
+ AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage, callingAttributionTag,
+ null)) {
case AppOpsManager.MODE_ALLOWED:
return true;
case AppOpsManager.MODE_DEFAULT:
@@ -498,8 +508,8 @@ public final class DropBoxManagerService extends SystemService {
}
public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis,
- String callingPackage) {
- if (!checkPermission(Binder.getCallingUid(), callingPackage)) {
+ String callingPackage, @Nullable String callingAttributionTag) {
+ if (!checkPermission(Binder.getCallingUid(), callingPackage, callingAttributionTag)) {
return null;
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index de96aaa1d940..7f6dc14f3793 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -127,6 +127,12 @@ public class GestureLauncherService extends SystemService {
* Whether camera double tap power button gesture is currently enabled;
*/
private boolean mCameraDoubleTapPowerEnabled;
+
+ /**
+ * Whether panic button gesture is currently enabled
+ */
+ private boolean mPanicButtonGestureEnabled;
+
private long mLastPowerDown;
private int mPowerButtonConsecutiveTaps;
@@ -141,10 +147,12 @@ public class GestureLauncherService extends SystemService {
mMetricsLogger = metricsLogger;
}
+ @Override
public void onStart() {
LocalServices.addService(GestureLauncherService.class, this);
}
+ @Override
public void onBootPhase(int phase) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
Resources resources = mContext.getResources();
@@ -160,6 +168,7 @@ public class GestureLauncherService extends SystemService {
"GestureLauncherService");
updateCameraRegistered();
updateCameraDoubleTapPowerEnabled();
+ updatePanicButtonGestureEnabled();
mUserId = ActivityManager.getCurrentUser();
mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
@@ -177,6 +186,9 @@ public class GestureLauncherService extends SystemService {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED),
false, mSettingObserver, mUserId);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.PANIC_GESTURE_ENABLED),
+ false, mSettingObserver, mUserId);
}
private void updateCameraRegistered() {
@@ -202,6 +214,14 @@ public class GestureLauncherService extends SystemService {
}
}
+ @VisibleForTesting
+ void updatePanicButtonGestureEnabled() {
+ boolean enabled = isPanicButtonGestureEnabled(mContext, mUserId);
+ synchronized (this) {
+ mPanicButtonGestureEnabled = enabled;
+ }
+ }
+
private void unregisterCameraLaunchGesture() {
if (mCameraLaunchRegistered) {
mCameraLaunchRegistered = false;
@@ -327,6 +347,15 @@ public class GestureLauncherService extends SystemService {
}
/**
+ * Whether to enable panic button gesture.
+ */
+ public static boolean isPanicButtonGestureEnabled(Context context, int userId) {
+ return isCameraLaunchEnabled(context.getResources())
+ && (Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.PANIC_GESTURE_ENABLED, 0, userId) != 0);
+ }
+
+ /**
* Whether to enable the camera launch gesture.
*/
public static boolean isCameraLaunchEnabled(Resources resources) {
@@ -445,6 +474,7 @@ public class GestureLauncherService extends SystemService {
registerContentObservers();
updateCameraRegistered();
updateCameraDoubleTapPowerEnabled();
+ updatePanicButtonGestureEnabled();
}
}
};
@@ -454,6 +484,7 @@ public class GestureLauncherService extends SystemService {
if (userId == mUserId) {
updateCameraRegistered();
updateCameraDoubleTapPowerEnabled();
+ updatePanicButtonGestureEnabled();
}
}
};
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index fd7abfa65c86..1689656479a5 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -23,6 +23,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.net.ConnectivityModuleConnector;
@@ -306,6 +307,8 @@ public class PackageWatchdog {
MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
if (pkg != null) {
packages.add(pkg);
+ } else {
+ Slog.w(TAG, "Failed to create MonitoredPackage for pkg=" + packageNames.get(i));
}
}
@@ -861,6 +864,25 @@ public class PackageWatchdog {
});
}
+ /**
+ * Gets PackageInfo for the given package. Matches any user and apex.
+ *
+ * @throws PackageManager.NameNotFoundException if no such package is installed.
+ */
+ private PackageInfo getPackageInfo(String packageName)
+ throws PackageManager.NameNotFoundException {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ // The MATCH_ANY_USER flag doesn't mix well with the MATCH_APEX
+ // flag, so make two separate attempts to get the package info.
+ // We don't need both flags at the same time because we assume
+ // apex files are always installed for all users.
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_ANY_USER);
+ } catch (PackageManager.NameNotFoundException e) {
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
+ }
+ }
+
@Nullable
private VersionedPackage getVersionedPackage(String packageName) {
final PackageManager pm = mContext.getPackageManager();
@@ -868,8 +890,7 @@ public class PackageWatchdog {
return null;
}
try {
- final long versionCode = pm.getPackageInfo(
- packageName, 0 /* flags */).getLongVersionCode();
+ final long versionCode = getPackageInfo(packageName).getLongVersionCode();
return new VersionedPackage(packageName, versionCode);
} catch (PackageManager.NameNotFoundException e) {
return null;
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 1cb7c4d18326..dd485fe3342f 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -25,6 +25,21 @@
{
"name": "CtsScopedStorageHostTest",
"file_patterns": ["StorageManagerService\\.java"]
+ },
+ {
+ "name": "FrameworksMockingServicesTests",
+ "file_patterns": ["AppStateTracker\\.java"],
+ "options": [
+ {
+ "include-filter": "com.android.server.AppStateTrackerTest"
+ },
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 56953708e383..3f867f656c24 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -18,7 +18,6 @@ package com.android.server.am;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
import static android.os.Process.NFC_UID;
import static android.os.Process.ROOT_UID;
@@ -1361,13 +1360,12 @@ public final class ActiveServices {
+ String.format("0x%08X", manifestType)
+ " in service element of manifest file");
}
- if ((foregroundServiceType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0
- && !r.mAllowWhileInUsePermissionInFgs) {
- // If the foreground service is not started from TOP process, do not allow it to
- // have location capability, this prevents BG started FGS to have while-in-use
- // location permission.
+ // If the foreground service is not started from TOP process, do not allow it to
+ // have while-in-use location/camera/microphone access.
+ if (!r.mAllowWhileInUsePermissionInFgs) {
Slog.w(TAG,
- "BG started FGS can not have location capability: service "
+ "Foreground service started from background can not have "
+ + "location/camera/microphone access: service "
+ r.shortInstanceName);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 25e6eb6e943f..fa18ccb53408 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6012,9 +6012,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private boolean isAppBad(ApplicationInfo info) {
+ private boolean isAppBad(final String processName, final int uid) {
synchronized (this) {
- return mAppErrors.isBadProcessLocked(info);
+ return mAppErrors.isBadProcessLocked(processName, uid);
}
}
@@ -6082,7 +6082,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]);
states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.getCurProcState();
if (scores != null) {
- scores[i] = isPendingTop ? ProcessList.FOREGROUND_APP_ADJ : pr.curAdj;
+ scores[i] = isPendingTop ? (ProcessList.FOREGROUND_APP_ADJ - 1) : pr.curAdj;
}
} else {
states[i] = PROCESS_STATE_NONEXISTENT;
@@ -19713,8 +19713,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public boolean isAppBad(ApplicationInfo info) {
- return ActivityManagerService.this.isAppBad(info);
+ public boolean isAppBad(final String processName, final int uid) {
+ return ActivityManagerService.this.isAppBad(processName, uid);
}
@Override
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 50d2cab0af81..a36a18b4cf5c 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -33,7 +33,6 @@ import android.app.ApplicationExitInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.VersionedPackage;
import android.net.Uri;
import android.os.Binder;
@@ -263,16 +262,16 @@ class AppErrors {
return needSep;
}
- boolean isBadProcessLocked(ApplicationInfo info) {
- return mBadProcesses.get(info.processName, info.uid) != null;
+ boolean isBadProcessLocked(final String processName, final int uid) {
+ return mBadProcesses.get(processName, uid) != null;
}
- void clearBadProcessLocked(ApplicationInfo info) {
- mBadProcesses.remove(info.processName, info.uid);
+ void clearBadProcessLocked(final String processName, final int uid) {
+ mBadProcesses.remove(processName, uid);
}
- void resetProcessCrashTimeLocked(ApplicationInfo info) {
- mProcessCrashTimes.remove(info.processName, info.uid);
+ void resetProcessCrashTimeLocked(final String processName, final int uid) {
+ mProcessCrashTimes.remove(processName, uid);
}
void resetProcessCrashTimeLocked(boolean resetEntireUser, int appId, int userId) {
@@ -548,7 +547,7 @@ class AppErrors {
if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
// XXX Can't keep track of crash time for isolated processes,
// since they don't have a persistent identity.
- mProcessCrashTimes.put(r.info.processName, r.uid,
+ mProcessCrashTimes.put(r.processName, r.uid,
SystemClock.uptimeMillis());
}
}
@@ -695,8 +694,8 @@ class AppErrors {
boolean tryAgain = false;
if (!app.isolated) {
- crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);
- crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid);
+ crashTime = mProcessCrashTimes.get(app.processName, app.uid);
+ crashTimePersistent = mProcessCrashTimesPersistent.get(app.processName, app.uid);
} else {
crashTime = crashTimePersistent = null;
}
@@ -723,10 +722,10 @@ class AppErrors {
if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {
// The process crashed again very quickly. If it was a bound foreground service, let's
// try to restart again in a while, otherwise the process loses!
- Slog.w(TAG, "Process " + app.info.processName
+ Slog.w(TAG, "Process " + app.processName
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
- app.userId, app.info.processName, app.uid);
+ app.userId, app.processName, app.uid);
mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
if (!app.isPersistent()) {
// We don't want to start this process again until the user
@@ -734,13 +733,13 @@ class AppErrors {
// need to keep it running. If a persistent process is actually
// repeatedly crashing, then badness for everyone.
EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
- app.info.processName);
+ app.processName);
if (!app.isolated) {
// XXX We don't have a way to mark isolated processes
// as bad, since they don't have a peristent identity.
- mBadProcesses.put(app.info.processName, app.uid,
+ mBadProcesses.put(app.processName, app.uid,
new BadProcessInfo(now, shortMsg, longMsg, stackTrace));
- mProcessCrashTimes.remove(app.info.processName, app.uid);
+ mProcessCrashTimes.remove(app.processName, app.uid);
}
app.bad = true;
app.removed = true;
@@ -785,8 +784,8 @@ class AppErrors {
if (!app.isolated) {
// XXX Can't keep track of crash times for isolated processes,
// because they don't have a persistent identity.
- mProcessCrashTimes.put(app.info.processName, app.uid, now);
- mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now);
+ mProcessCrashTimes.put(app.processName, app.uid, now);
+ mProcessCrashTimesPersistent.put(app.processName, app.uid, now);
}
if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);
@@ -829,7 +828,7 @@ class AppErrors {
}
Long crashShowErrorTime = null;
if (!proc.isolated) {
- crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.info.processName,
+ crashShowErrorTime = mProcessCrashShowDialogTimes.get(proc.processName,
proc.uid);
}
final boolean showFirstCrash = Settings.Global.getInt(
@@ -850,7 +849,7 @@ class AppErrors {
&& (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
proc.getDialogController().showCrashDialogs(data);
if (!proc.isolated) {
- mProcessCrashShowDialogTimes.put(proc.info.processName, proc.uid, now);
+ mProcessCrashShowDialogTimes.put(proc.processName, proc.uid, now);
}
} else {
// The device is asleep, so just pretend that the user
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 02fb34e73f7f..374c215fc6d0 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -522,7 +522,7 @@ public final class AppExitInfoTracker {
AppExitInfoContainer container = records.get(filterUid);
if (container != null) {
mTmpInfoList.clear();
- results.addAll(container.toListLocked(mTmpInfoList, filterPid));
+ list.addAll(container.toListLocked(mTmpInfoList, filterPid));
}
return AppExitInfoTracker.FOREACH_ACTION_NONE;
});
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a2eea1348d5c..1fa62c6c40ba 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -604,7 +604,7 @@ public final class BroadcastQueue {
}
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
- BroadcastFilter filter, boolean ordered, int index) {
+ BroadcastFilter filter, boolean ordered, int index, boolean skipOomAdj) {
boolean skip = false;
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
@@ -788,8 +788,10 @@ public final class BroadcastQueue {
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceivers.add(r);
- mService.updateOomAdjLocked(r.curApp, true,
- OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ if (!skipOomAdj) {
+ mService.updateOomAdjLocked(r.curApp, true,
+ OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
+ }
}
}
try {
@@ -985,7 +987,8 @@ public final class BroadcastQueue {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
- deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
+ deliverToRegisteredReceiverLocked(r,
+ (BroadcastFilter) target, false, i, skipOomAdj);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
@@ -1037,7 +1040,7 @@ public final class BroadcastQueue {
// No more broadcasts are deliverable right now, so all done!
mDispatcher.scheduleDeferralCheckLocked(false);
mService.scheduleAppGcsLocked();
- if (looped) {
+ if (looped && !skipOomAdj) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
@@ -1283,7 +1286,7 @@ public final class BroadcastQueue {
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx, skipOomAdj);
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ebff0691c1f7..b6ad1a526165 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2359,9 +2359,9 @@ public final class ProcessList {
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
- if (mService.mAppErrors.isBadProcessLocked(info)) {
+ if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
- + "/" + info.processName);
+ + "/" + processName);
return null;
}
} else {
@@ -2370,13 +2370,13 @@ public final class ProcessList {
// least one crash dialog again, and make the process good again
// if it had been bad.
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
- + "/" + info.processName);
- mService.mAppErrors.resetProcessCrashTimeLocked(info);
- if (mService.mAppErrors.isBadProcessLocked(info)) {
+ + "/" + processName);
+ mService.mAppErrors.resetProcessCrashTimeLocked(processName, info.uid);
+ if (mService.mAppErrors.isBadProcessLocked(processName, info.uid)) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
- mService.mAppErrors.clearBadProcessLocked(info);
+ mService.mAppErrors.clearBadProcessLocked(processName, info.uid);
if (app != null) {
app.bad = false;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 2eca00e27ddf..b3231909e4b7 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -44,6 +44,7 @@ import static android.app.AppOpsManager.RestrictionBypass;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
+import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
import static android.app.AppOpsManager.UID_STATE_CACHED;
@@ -5936,11 +5937,13 @@ public class AppOpsService extends IAppOpsService.Stub {
int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
mSampledAppOpCode, _NUM_OP);
- if (mAcceptableLeftDistance < newLeftDistance) {
+ if (mAcceptableLeftDistance < newLeftDistance
+ && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
return;
}
- if (mAcceptableLeftDistance > newLeftDistance) {
+ if (mAcceptableLeftDistance > newLeftDistance
+ && mSamplingStrategy != SAMPLING_STRATEGY_UNIFORM_OPS) {
mAcceptableLeftDistance = newLeftDistance;
mMessagesCollectedCount = 0.0f;
}
@@ -5978,13 +5981,13 @@ public class AppOpsService extends IAppOpsService.Stub {
if (mSampledPackage == null) {
if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
mSamplingStrategy = SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
- resampleAppOpForPackageLocked(packageName);
+ resampleAppOpForPackageLocked(packageName, true);
}
} else if (mRarelyUsedPackages.contains(packageName)) {
mRarelyUsedPackages.remove(packageName);
if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
mSamplingStrategy = SAMPLING_STRATEGY_RARELY_USED;
- resampleAppOpForPackageLocked(packageName);
+ resampleAppOpForPackageLocked(packageName, true);
}
}
}
@@ -6001,16 +6004,22 @@ public class AppOpsService extends IAppOpsService.Stub {
/** Resamples package and appop to watch from the list provided. */
private void resamplePackageAndAppOpLocked(@NonNull List<String> packageNames) {
if (!packageNames.isEmpty()) {
- mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
- resampleAppOpForPackageLocked(packageNames.get(
- ThreadLocalRandom.current().nextInt(packageNames.size())));
+ if (ThreadLocalRandom.current().nextFloat() < 0.5f) {
+ mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM;
+ resampleAppOpForPackageLocked(packageNames.get(
+ ThreadLocalRandom.current().nextInt(packageNames.size())), true);
+ } else {
+ mSamplingStrategy = SAMPLING_STRATEGY_UNIFORM_OPS;
+ resampleAppOpForPackageLocked(packageNames.get(
+ ThreadLocalRandom.current().nextInt(packageNames.size())), false);
+ }
}
}
/** Resamples appop for the chosen package and initializes sampling state */
- private void resampleAppOpForPackageLocked(@NonNull String packageName) {
+ private void resampleAppOpForPackageLocked(@NonNull String packageName, boolean pickOp) {
mMessagesCollectedCount = 0.0f;
- mSampledAppOpCode = ThreadLocalRandom.current().nextInt(_NUM_OP);
+ mSampledAppOpCode = pickOp ? ThreadLocalRandom.current().nextInt(_NUM_OP) : OP_NONE;
mAcceptableLeftDistance = _NUM_OP;
mSampledPackage = packageName;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c8e4ee02e603..c45cefe5bf0c 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2956,11 +2956,10 @@ public class AudioService extends IAudioService.Stub
// Don't show volume UI when:
// - Hdmi-CEC system audio mode is on and we are a TV panel
- // - CEC volume control enabled on a set-top box
private int updateFlagsForTvPlatform(int flags) {
synchronized (mHdmiClientLock) {
- if ((mHdmiTvClient != null && mHdmiSystemAudioSupported && mHdmiCecVolumeControlEnabled)
- || (mHdmiPlaybackClient != null && mHdmiCecVolumeControlEnabled)) {
+ if (mHdmiTvClient != null && mHdmiSystemAudioSupported
+ && mHdmiCecVolumeControlEnabled) {
flags &= ~AudioManager.FLAG_SHOW_UI;
}
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index b8c639ceb8ba..a47904c40cc3 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -28,6 +28,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRIN
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_IRIS;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.IAuthService;
@@ -127,6 +128,11 @@ public class AuthService extends SystemService {
return IIrisService.Stub.asInterface(
ServiceManager.getService(Context.IRIS_SERVICE));
}
+
+ @VisibleForTesting
+ public AppOpsManager getAppOps(Context context) {
+ return context.getSystemService(AppOpsManager.class);
+ }
}
private final class AuthServiceImpl extends IAuthService.Stub {
@@ -137,6 +143,8 @@ public class AuthService extends SystemService {
// Only allow internal clients to authenticate with a different userId.
final int callingUserId = UserHandle.getCallingUserId();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
if (userId == callingUserId) {
checkPermission();
} else {
@@ -145,6 +153,16 @@ public class AuthService extends SystemService {
checkInternalPermission();
}
+ if (!checkAppOps(callingUid, opPackageName, "authenticate()")) {
+ Slog.e(TAG, "Denied by app ops: " + opPackageName);
+ return;
+ }
+
+ if (!Utils.isForeground(callingUid, callingPid)) {
+ Slog.e(TAG, "Caller is not foreground: " + opPackageName);
+ return;
+ }
+
if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
Slog.e(TAG, "Unable to authenticate, one or more null arguments");
return;
@@ -155,8 +173,6 @@ public class AuthService extends SystemService {
checkInternalPermission();
}
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
final long identity = Binder.clearCallingIdentity();
try {
mBiometricService.authenticate(
@@ -370,4 +386,9 @@ public class AuthService extends SystemService {
"Must have USE_BIOMETRIC permission");
}
}
+
+ private boolean checkAppOps(int uid, String opPackageName, String reason) {
+ return mInjector.getAppOps(getContext()).noteOp(AppOpsManager.OP_USE_BIOMETRIC, uid,
+ opPackageName, null /* attributionTag */, reason) == AppOpsManager.MODE_ALLOWED;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index 29b8493b8035..88fd44456ff6 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -17,8 +17,12 @@
package com.android.server.biometrics;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
import static android.hardware.biometrics.BiometricManager.Authenticators;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.server.biometrics.PreAuthInfo.AUTHENTICATOR_OK;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_DISABLED_BY_DEVICE_POLICY;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_HARDWARE_NOT_DETECTED;
@@ -31,6 +35,8 @@ import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NOT_ENROLLED;
import static com.android.server.biometrics.PreAuthInfo.BIOMETRIC_NO_HARDWARE;
import static com.android.server.biometrics.PreAuthInfo.CREDENTIAL_NOT_ENROLLED;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -52,6 +58,10 @@ import android.provider.Settings;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.biometrics.sensors.ClientMonitor;
+
+import java.util.List;
public class Utils {
@@ -395,4 +405,43 @@ public class Utils {
? keyguardComponent.getPackageName() : null;
return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage);
}
+
+ public static String getClientName(@Nullable ClientMonitor<?> client) {
+ return client != null ? client.getClass().getSimpleName() : "null";
+ }
+
+ private static boolean containsFlag(int haystack, int needle) {
+ return (haystack & needle) != 0;
+ }
+
+ public static boolean isUserEncryptedOrLockdown(@NonNull LockPatternUtils lpu, int user) {
+ final int strongAuth = lpu.getStrongAuthForUser(user);
+ final boolean isEncrypted = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT);
+ final boolean isLockDown = containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+ || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ Slog.d(TAG, "isEncrypted: " + isEncrypted + " isLockdown: " + isLockDown);
+ return isEncrypted || isLockDown;
+ }
+
+ public static boolean isForeground(int callingUid, int callingPid) {
+ try {
+ final List<ActivityManager.RunningAppProcessInfo> procs =
+ ActivityManager.getService().getRunningAppProcesses();
+ if (procs == null) {
+ Slog.e(TAG, "No running app processes found, defaulting to true");
+ return true;
+ }
+
+ for (int i = 0; i < procs.size(); i++) {
+ ActivityManager.RunningAppProcessInfo proc = procs.get(i);
+ if (proc.pid == callingPid && proc.uid == callingUid
+ && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
+ return true;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "am.getRunningAppProcesses() failed");
+ }
+ return false;
+ }
}
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 14baaa72494f..ab48fdb0fd6e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -45,14 +45,15 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
private final PowerManager mPowerManager;
private final VibrationEffect mSuccessVibrationEffect;
private final VibrationEffect mErrorVibrationEffect;
- private boolean mErrorAlreadySent;
+ private boolean mShouldSendErrorToClient;
+ private boolean mAlreadyCancelled;
/**
* Stops the HAL operation specific to the ClientMonitor subclass.
*/
protected abstract void stopHalOperation();
- AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
+ 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) {
@@ -84,11 +85,11 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
// case (success, failure, or error) is received from the HAL (e.g. versions of fingerprint
// that do not handle lockout under the HAL. In these cases, ensure that the framework only
// sends errors once per ClientMonitor.
- if (!mErrorAlreadySent) {
+ if (!mShouldSendErrorToClient) {
logOnError(getContext(), errorCode, vendorCode, getTargetUserId());
try {
if (getListener() != null) {
- mErrorAlreadySent = true;
+ mShouldSendErrorToClient = true;
getListener().onError(getSensorId(), getCookie(), errorCode, vendorCode);
}
} catch (RemoteException e) {
@@ -102,6 +103,17 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
}
@Override
+ public void cancel() {
+ if (mAlreadyCancelled) {
+ Slog.w(TAG, "Cancel was already requested");
+ return;
+ }
+
+ stopHalOperation();
+ mAlreadyCancelled = true;
+ }
+
+ @Override
public void cancelWithoutStarting(@NonNull FinishCallback finishCallback) {
final int errorCode = BiometricConstants.BIOMETRIC_ERROR_CANCELED;
try {
@@ -153,7 +165,7 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
}
- final void vibrateSuccess() {
+ protected final void vibrateSuccess() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
if (vibrator != null) {
vibrator.vibrate(mSuccessVibrationEffect, VIBRATION_SONFICATION_ATTRIBUTES);
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 5392f0ff89af..cb2321f524f6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
@@ -34,21 +35,21 @@ import java.util.ArrayList;
/**
* A class to keep track of the authentication state for a given client.
*/
-public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
+public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
+ implements AuthenticationConsumer {
private static final String TAG = "Biometrics/AuthenticationClient";
private final boolean mIsStrongBiometric;
private final boolean mRequireConfirmation;
private final IActivityTaskManager mActivityTaskManager;
- private final TaskStackListener mTaskStackListener;
+ @Nullable private final TaskStackListener mTaskStackListener;
private final LockoutTracker mLockoutTracker;
private final boolean mIsRestricted;
protected final long mOperationId;
private long mStartTimeMs;
- private boolean mAlreadyCancelled;
protected boolean mAuthAttempted;
@@ -56,7 +57,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
int targetUserId, long operationId, boolean restricted, @NonNull String owner,
int cookie, boolean requireConfirmation, int sensorId, boolean isStrongBiometric,
- int statsModality, int statsClient, @NonNull TaskStackListener taskStackListener,
+ int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
@@ -103,6 +104,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
return mOperationId != 0;
}
+ @Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> hardwareAuthToken) {
super.logOnAuthenticated(getContext(), authenticated, mRequireConfirmation,
@@ -133,10 +135,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
vibrateSuccess();
}
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not unregister task stack listener", e);
+ if (mTaskStackListener != null) {
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not unregister task stack listener", e);
+ }
}
final byte[] byteToken = new byte[hardwareAuthToken.size()];
@@ -221,10 +225,12 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
return;
}
- try {
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not register task stack listener", e);
+ if (mTaskStackListener != null) {
+ try {
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not register task stack listener", e);
+ }
}
if (DEBUG) Slog.w(TAG, "Requesting auth for " + getOwnerString());
@@ -236,20 +242,14 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T> {
@Override
public void cancel() {
- if (mAlreadyCancelled) {
- Slog.w(TAG, "stopAuthentication: already cancelled!");
- return;
- }
+ super.cancel();
- try {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "Could not unregister task stack listener", e);
+ if (mTaskStackListener != null) {
+ try {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Could not unregister task stack listener", e);
+ }
}
-
- if (DEBUG) Slog.w(TAG, "Requesting cancel for " + getOwnerString());
-
- stopHalOperation();
- mAlreadyCancelled = true;
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationConsumer.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationConsumer.java
new file mode 100644
index 000000000000..09a577eb2825
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.biometrics.sensors;
+
+import android.hardware.biometrics.BiometricAuthenticator;
+
+import java.util.ArrayList;
+
+/**
+ * Interface that clients interested/eligible for authentication events should implement.
+ */
+public interface AuthenticationConsumer {
+ void onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated,
+ ArrayList<Byte> hardwareAuthToken);
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index c9ab3138b410..0aeb7abe706e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -28,7 +28,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
-import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityTracker;
+import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -37,7 +37,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Date;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Queue;
@@ -133,7 +132,7 @@ public class BiometricScheduler {
@Override
public void run() {
if (operation.state != Operation.STATE_FINISHED) {
- Slog.e(tag, "[Watchdog] Running for: " + operation);
+ Slog.e(tag, "[Watchdog Triggered]: " + operation);
operation.clientMonitor.mFinishCallback
.onClientFinished(operation.clientMonitor, false /* success */);
}
@@ -173,7 +172,7 @@ public class BiometricScheduler {
}
@NonNull private final String mBiometricTag;
- @Nullable private final GestureAvailabilityTracker mGestureAvailabilityTracker;
+ @Nullable private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
@NonNull private final IBiometricService mBiometricService;
@NonNull private final Handler mHandler = new Handler(Looper.getMainLooper());
@NonNull private final InternalFinishCallback mInternalFinishCallback;
@@ -195,6 +194,8 @@ public class BiometricScheduler {
return;
}
+ mCurrentOperation.state = Operation.STATE_FINISHED;
+
if (mCurrentOperation.clientFinishCallback != null) {
mCurrentOperation.clientFinishCallback.onClientFinished(clientMonitor, success);
}
@@ -206,12 +207,11 @@ public class BiometricScheduler {
}
Slog.d(getTag(), "[Finished] " + clientMonitor + ", success: " + success);
- if (mGestureAvailabilityTracker != null) {
- mGestureAvailabilityTracker.markSensorActive(
+ if (mGestureAvailabilityDispatcher != null) {
+ mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.clientMonitor.getSensorId(), false /* active */);
}
- mCurrentOperation.state = Operation.STATE_FINISHED;
mCurrentOperation = null;
startNextOperationIfIdle();
});
@@ -221,15 +221,15 @@ public class BiometricScheduler {
/**
* Creates a new scheduler.
* @param tag for the specific instance of the scheduler. Should be unique.
- * @param gestureAvailabilityTracker may be null if the sensor does not support gestures (such
- * as fingerprint swipe).
+ * @param gestureAvailabilityDispatcher may be null if the sensor does not support gestures
+ * (such as fingerprint swipe).
*/
public BiometricScheduler(@NonNull String tag,
- @Nullable GestureAvailabilityTracker gestureAvailabilityTracker) {
+ @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
mBiometricTag = tag;
mInternalFinishCallback = new InternalFinishCallback();
- mGestureAvailabilityTracker = gestureAvailabilityTracker;
- mPendingOperations = new LinkedList<>();
+ mGestureAvailabilityDispatcher = gestureAvailabilityDispatcher;
+ mPendingOperations = new ArrayDeque<>();
mBiometricService = IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE));
mCrashStates = new ArrayDeque<>();
@@ -268,9 +268,9 @@ public class BiometricScheduler {
return;
}
- if (mGestureAvailabilityTracker != null
+ if (mGestureAvailabilityDispatcher != null
&& mCurrentOperation.clientMonitor instanceof AcquisitionClient) {
- mGestureAvailabilityTracker.markSensorActive(
+ mGestureAvailabilityDispatcher.markSensorActive(
mCurrentOperation.clientMonitor.getSensorId(),
true /* active */);
}
@@ -297,15 +297,23 @@ public class BiometricScheduler {
* Starts the {@link #mCurrentOperation} if
* 1) its state is {@link Operation#STATE_WAITING_FOR_COOKIE} and
* 2) its cookie matches this cookie
+ *
+ * This is currently only used by {@link com.android.server.biometrics.BiometricService}, which
+ * requests sensors to prepare for authentication with a cookie. Once sensor(s) are ready (e.g.
+ * the BiometricService client becomes the current client in the scheduler), the cookie is
+ * returned to BiometricService. Once BiometricService decides that authentication can start,
+ * it invokes this code path.
+ *
* @param cookie of the operation to be started
*/
public void startPreparedClient(int cookie) {
if (mCurrentOperation == null) {
- Slog.e(getTag(), "Current operation null");
+ Slog.e(getTag(), "Current operation is null");
return;
}
if (mCurrentOperation.state != Operation.STATE_WAITING_FOR_COOKIE) {
- Slog.e(getTag(), "Operation in wrong state: " + mCurrentOperation);
+ Slog.e(getTag(), "Operation is in the wrong state: " + mCurrentOperation
+ + ", expected STATE_WAITING_FOR_COOKIE");
return;
}
if (mCurrentOperation.clientMonitor.getCookie() != cookie) {
@@ -354,7 +362,8 @@ public class BiometricScheduler {
// If the current operation is cancellable, start the cancellation process.
if (mCurrentOperation != null && mCurrentOperation.clientMonitor instanceof Interruptable
- && mCurrentOperation.state != Operation.STATE_STARTED_CANCELING) {
+ && mCurrentOperation.state == Operation.STATE_STARTED) {
+ Slog.d(getTag(), "[Cancelling Interruptable]: " + mCurrentOperation);
cancelInternal(mCurrentOperation);
}
@@ -415,7 +424,7 @@ public class BiometricScheduler {
return;
}
final boolean isAuthenticating =
- mCurrentOperation.clientMonitor instanceof AuthenticationClient;
+ mCurrentOperation.clientMonitor instanceof AuthenticationConsumer;
final boolean tokenMatches = mCurrentOperation.clientMonitor.getToken() == token;
if (!isAuthenticating || !tokenMatches) {
Slog.w(getTag(), "Not cancelling authentication, isEnrolling: " + isAuthenticating
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
deleted file mode 100644
index 9aa72a76aed2..000000000000
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricServiceBase.java
+++ /dev/null
@@ -1,681 +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.server.biometrics.sensors;
-
-import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
-
-import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
-import android.app.AppOpsManager;
-import android.app.IActivityTaskManager;
-import android.app.SynchronousUserSwitchObserver;
-import android.app.TaskStackListener;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricConstants;
-import android.hardware.biometrics.BiometricsProtoEnums;
-import android.hardware.biometrics.IBiometricService;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IHwBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.SystemService;
-import com.android.server.biometrics.Utils;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Abstract base class containing all of the business logic for biometric services, e.g.
- * Fingerprint, Face, Iris.
- *
- * @hide
- */
-public abstract class BiometricServiceBase<T> extends SystemService
- implements IHwBinder.DeathRecipient {
-
- protected static final boolean DEBUG = true;
-
- private static final int MSG_USER_SWITCHING = 10;
- private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
-
- private final Context mContext;
- protected final IActivityTaskManager mActivityTaskManager;
- protected final BiometricTaskStackListener mTaskStackListener =
- new BiometricTaskStackListener();
- private final ResetClientStateRunnable mResetClientState = new ResetClientStateRunnable();
-
- protected final IStatusBarService mStatusBarService;
- protected final Map<Integer, Long> mAuthenticatorIds =
- Collections.synchronizedMap(new HashMap<>());
- protected final AppOpsManager mAppOps;
-
- /**
- * Handler which all subclasses should post events to.
- */
- protected final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case MSG_USER_SWITCHING:
- handleUserSwitching(msg.arg1);
- break;
- default:
- Slog.w(getTag(), "Unknown message:" + msg.what);
- }
- }
- };
-
- protected final ClientMonitor.FinishCallback mClientFinishCallback =
- (clientMonitor, success) -> {
- removeClient(clientMonitor);
- // When enrollment finishes, update this group's authenticator id, as the HAL has
- // already generated a new authenticator id when the new biometric is enrolled.
- if (clientMonitor instanceof EnrollClient) {
- updateActiveGroup(clientMonitor.getTargetUserId());
- }
- };
-
- private IBiometricService mBiometricService;
- private ClientMonitor<T> mCurrentClient;
- private ClientMonitor<T> mPendingClient;
- private PerformanceTracker mPerformanceTracker;
- private int mSensorId;
- protected int mCurrentUserId = UserHandle.USER_NULL;
-
- /**
- * @return the log tag.
- */
- protected abstract String getTag();
-
- /**
- * @return a fresh reference to the biometric HAL
- */
- protected abstract T getDaemon();
-
- /**
- * @return the biometric utilities for a specific implementation.
- */
- protected abstract BiometricUtils getBiometricUtils();
-
- /**
- * @param userId
- * @return true if the enrollment limit has been reached.
- */
- protected abstract boolean hasReachedEnrollmentLimit(int userId);
-
- /**
- * Notifies the HAL that the user has changed.
- * @param userId
- */
- protected abstract void updateActiveGroup(int userId);
-
- /**
- * @param userId
- * @return Returns true if the user has any enrolled biometrics.
- */
- protected abstract boolean hasEnrolledBiometrics(int userId);
-
- /**
- * @return Returns the MANAGE_* permission string, which is required for enrollment, removal
- * etc.
- */
- protected abstract String getManageBiometricPermission();
-
- protected abstract List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(
- int userId);
-
- /**
- * Notifies clients of any change in the biometric state (active / idle). This is mainly for
- * Fingerprint navigation gestures.
- * @param isActive
- */
- protected void notifyClientActiveCallbacks(boolean isActive) {}
-
- protected abstract int statsModality();
-
- private final Runnable mOnTaskStackChangedRunnable = new Runnable() {
- @Override
- public void run() {
- try {
- if (!(mCurrentClient instanceof AuthenticationClient)) {
- return;
- }
- final String currentClient = mCurrentClient.getOwnerString();
- if (isKeyguard(currentClient)) {
- return; // Keyguard is always allowed
- }
- List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(currentClient)
- && !mCurrentClient.isAlreadyDone()) {
- Slog.e(getTag(), "Stopping background authentication, top: "
- + topPackage + " currentClient: " + currentClient);
- ((AuthenticationClient) mCurrentClient).cancel();
- }
- }
- } catch (RemoteException e) {
- Slog.e(getTag(), "Unable to get running tasks", e);
- }
- }
- };
-
- private final class BiometricTaskStackListener extends TaskStackListener {
- @Override
- public void onTaskStackChanged() {
- mHandler.post(mOnTaskStackChangedRunnable);
- }
- }
-
- private final class ResetClientStateRunnable implements Runnable {
- @Override
- public void run() {
- /**
- * Warning: if we get here, the driver never confirmed our call to cancel the current
- * operation (authenticate, enroll, remove, enumerate, etc), which is
- * really bad. The result will be a 3-second delay in starting each new client.
- * If you see this on a device, make certain the driver notifies with
- * {@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} in response to cancel()
- * once it has successfully switched to the IDLE state in the HAL.
- * Additionally,{@link BiometricConstants#BIOMETRIC_ERROR_CANCELED} should only be sent
- * in response to an actual cancel() call.
- */
- Slog.w(getTag(), "Client "
- + (mCurrentClient != null ? mCurrentClient.getOwnerString() : "null")
- + " failed to respond to cancel, starting client "
- + (mPendingClient != null ? mPendingClient.getOwnerString() : "null"));
-
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- statsModality(), BiometricsProtoEnums.ISSUE_CANCEL_TIMED_OUT);
-
- ClientMonitor<T> newClient = mPendingClient;
- mCurrentClient = null;
- mPendingClient = null;
- startClient(newClient, false);
- }
- }
-
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public BiometricServiceBase(Context context) {
- super(context);
- mContext = context;
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mAppOps = context.getSystemService(AppOpsManager.class);
- mActivityTaskManager = ActivityTaskManager.getService();
- mPerformanceTracker = PerformanceTracker.getInstanceForSensorId(getSensorId());
- }
-
- @Override
- public void onStart() {
- listenForUserSwitches();
- }
-
- @Override
- public void serviceDied(long cookie) {
- Slog.e(getTag(), "HAL died");
- mPerformanceTracker.incrementHALDeathCount();
- mCurrentUserId = UserHandle.USER_NULL;
-
- // All client lifecycle must be managed on the handler.
- mHandler.post(() -> {
- Slog.e(getTag(), "Sending BIOMETRIC_ERROR_HW_UNAVAILABLE after HAL crash");
- handleError(BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
- });
-
- FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
- statsModality(), BiometricsProtoEnums.ISSUE_HAL_DEATH);
- }
-
- protected void initializeConfigurationInternal(int sensorId) {
- if (DEBUG) {
- Slog.d(getTag(), "initializeConfigurationInternal(" + sensorId + ")");
- }
- mSensorId = sensorId;
- }
-
- protected ClientMonitor<?> getCurrentClient() {
- return mCurrentClient;
- }
-
- protected boolean isStrongBiometric() {
- return Utils.isStrongBiometric(mSensorId);
- }
-
- protected int getSensorId() {
- return mSensorId;
- }
-
- /**
- * Callback handlers from the daemon. The caller must put this on a handler.
- */
-
- protected void handleAcquired(int acquiredInfo, int vendorCode) {
- final ClientMonitor<?> client = mCurrentClient;
- if (!(client instanceof AcquisitionClient)) {
- final String clientName = client != null ? client.getClass().getSimpleName() : "null";
- Slog.e(getTag(), "handleAcquired for non-acquire consumer: " + clientName);
- return;
- }
-
- final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
- acquisitionClient.onAcquired(acquiredInfo, vendorCode);
- }
-
- protected void handleAuthenticated(BiometricAuthenticator.Identifier identifier,
- ArrayList<Byte> token) {
- final ClientMonitor<?> client = mCurrentClient;
- if (!(client instanceof AuthenticationClient)) {
- final String clientName = client != null ? client.getClass().getSimpleName() : "null";
- Slog.e(getTag(), "handleAuthenticated for non-authentication client: " + clientName);
- return;
- }
-
- final AuthenticationClient<?> authenticationClient = (AuthenticationClient<?>) client;
- final boolean authenticated = identifier.getBiometricId() != 0;
- authenticationClient.onAuthenticated(identifier, authenticated, token);
- }
-
- protected void handleEnrollResult(BiometricAuthenticator.Identifier identifier,
- int remaining) {
- final ClientMonitor<?> client = mCurrentClient;
- if (!(client instanceof EnrollClient)) {
- final String clientName = client != null ? client.getClass().getSimpleName() : "null";
- Slog.e(getTag(), "handleEnrollResult for non-enroll client: " + clientName);
- return;
- }
-
- final EnrollClient<?> enrollClient = (EnrollClient<?>) client;
- enrollClient.onEnrollResult(identifier, remaining);
- }
-
- protected void handleError(int error, int vendorCode) {
- final ClientMonitor<?> client = mCurrentClient;
-
- if (DEBUG) Slog.v(getTag(), "handleError(client="
- + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
-
- if (!(client instanceof Interruptable)) {
- Slog.e(getTag(), "error received for non-ErrorConsumer");
- return;
- }
-
- final Interruptable interruptable = (Interruptable) client;
- interruptable.onError(error, vendorCode);
-
- if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
- mHandler.removeCallbacks(mResetClientState);
- if (mPendingClient != null) {
- if (DEBUG) Slog.v(getTag(), "start pending client " +
- mPendingClient.getOwnerString());
- startClient(mPendingClient, false);
- mPendingClient = null;
- }
- }
- }
-
- protected void handleRemoved(BiometricAuthenticator.Identifier identifier,
- final int remaining) {
- if (DEBUG) Slog.w(getTag(), "Removed: fid=" + identifier.getBiometricId()
- + ", dev=" + identifier.getDeviceId()
- + ", rem=" + remaining);
-
- final ClientMonitor<?> client = mCurrentClient;
- if (!(client instanceof RemovalConsumer)) {
- final String clientName = client != null ? client.getClass().getSimpleName() : "null";
- Slog.e(getTag(), "handleRemoved for non-removal consumer: " + clientName);
- return;
- }
-
- final RemovalConsumer removalConsumer = (RemovalConsumer) client;
- removalConsumer.onRemoved(identifier, remaining);
- }
-
- protected void handleEnumerate(BiometricAuthenticator.Identifier identifier, int remaining) {
- final ClientMonitor<?> client = mCurrentClient;
- if (!(client instanceof EnumerateConsumer)) {
- final String clientName = client != null ? client.getClass().getSimpleName() : "null";
- Slog.e(getTag(), "handleEnumerate for non-enumerate consumer: "
- + clientName);
- return;
- }
-
- final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
- enumerateConsumer.onEnumerationResult(identifier, remaining);
- }
-
- /**
- * Calls from the Manager. These are still on the calling binder's thread.
- */
-
- protected void enrollInternal(EnrollClient<T> client, int userId) {
- if (hasReachedEnrollmentLimit(userId)) {
- return;
- }
-
- // Group ID is arbitrarily set to parent profile user ID. It just represents
- // the default biometrics for the user.
- if (!Utils.isCurrentUserOrProfile(mContext, userId)) {
- return;
- }
-
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void cancelEnrollmentInternal(IBinder token) {
- mHandler.post(() -> {
- ClientMonitor<?> client = mCurrentClient;
- if (client instanceof EnrollClient && client.getToken() == token) {
- if (DEBUG) Slog.v(getTag(), "Cancelling enrollment");
- ((EnrollClient<?>) client).cancel();
- }
- });
- }
-
- protected void generateChallengeInternal(GenerateChallengeClient<T> client) {
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void revokeChallengeInternal(RevokeChallengeClient<T> client) {
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void authenticateInternal(AuthenticationClient<T> client, String opPackageName) {
- mHandler.post(() -> {
- startAuthentication(client, opPackageName);
- });
- }
-
- protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
- boolean fromClient) {
-
- if (DEBUG) Slog.v(getTag(), "cancelAuthentication(" + opPackageName + ")");
-
- mHandler.post(() -> {
- ClientMonitor<?> client = mCurrentClient;
- if (client instanceof AuthenticationClient) {
- if (client.getToken() == token || !fromClient) {
- if (DEBUG) Slog.v(getTag(), "Stopping client " + client.getOwnerString()
- + ", fromClient: " + fromClient);
- // If cancel was from BiometricService, it means the dialog was dismissed
- // and authentication should be canceled.
- ((AuthenticationClient<?>) client).cancel();
- } else {
- if (DEBUG) Slog.v(getTag(), "Can't stop client " + client.getOwnerString()
- + " since tokens don't match. fromClient: " + fromClient);
- }
- } else if (client != null) {
- if (DEBUG) Slog.v(getTag(), "Can't cancel non-authenticating client "
- + client.getOwnerString());
- }
- });
- }
-
- protected void removeInternal(RemovalClient<T> client) {
- mHandler.post(() -> {
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- protected void cleanupInternal(
- InternalCleanupClient<? extends BiometricAuthenticator.Identifier, T> client) {
- mHandler.post(() -> {
- if (DEBUG) {
- Slog.v(getTag(), "Cleaning up templates for user("
- + client.getTargetUserId() + ")");
- }
- startClient(client, true /* initiatedByClient */);
- });
- }
-
- // Should be done on a handler thread - not on the Binder's thread.
- private void startAuthentication(AuthenticationClient<T> client, String opPackageName) {
- if (DEBUG) Slog.v(getTag(), "startAuthentication(" + opPackageName + ")");
-
- startClient(client, true /* initiatedByClient */);
- }
-
- /**
- * Helper methods.
- */
-
- /**
- * @return true if this is keyguard package
- */
- public boolean isKeyguard(String clientPackage) {
- return Utils.isKeyguard(mContext, clientPackage);
- }
-
- /**
- * Calls the HAL to switch states to the new task. If there's already a current task,
- * it calls cancel() and sets mPendingClient to begin when the current task finishes
- * ({@link BiometricConstants#BIOMETRIC_ERROR_CANCELED}).
- *
- * @param newClient the new client that wants to connect
- * @param initiatedByClient true for authenticate, remove and enroll
- */
- @VisibleForTesting
- protected void startClient(ClientMonitor<T> newClient, boolean initiatedByClient) {
- ClientMonitor<?> currentClient = mCurrentClient;
- if (currentClient != null) {
- if (DEBUG) Slog.v(getTag(), "request stop current client " +
- currentClient.getOwnerString());
- if (currentClient instanceof InternalCleanupClient) {
- // This condition means we're currently running internal diagnostics to
- // remove extra templates in the hardware and/or the software
- // TODO: design an escape hatch in case client never finishes
- if (newClient != null) {
- Slog.w(getTag(), "Internal cleanup in progress but trying to start client "
- + newClient.getClass().getSuperclass().getSimpleName()
- + "(" + newClient.getOwnerString() + ")"
- + ", initiatedByClient = " + initiatedByClient);
- }
- } else if (currentClient instanceof Interruptable) {
- ((Interruptable) currentClient).cancel();
-
- // Only post the reset runnable for non-cleanup clients. Cleanup clients should
- // never be forcibly stopped since they ensure synchronization between HAL and
- // framework. Thus, we should instead just start the pending client once cleanup
- // finishes instead of using the reset runnable.
- mHandler.removeCallbacks(mResetClientState);
- mHandler.postDelayed(mResetClientState, CANCEL_TIMEOUT_LIMIT);
- }
- mPendingClient = newClient;
- } else if (newClient != null) {
- // For BiometricPrompt clients, do not start until
- // <Biometric>Service#startPreparedClient is called. BiometricService waits until all
- // modalities are ready before initiating authentication.
- if (newClient instanceof AuthenticationClient) {
- AuthenticationClient<?> client = (AuthenticationClient<?>) newClient;
- if (client.isBiometricPrompt()) {
- if (DEBUG) Slog.v(getTag(), "Returning cookie: " + client.getCookie());
- mCurrentClient = newClient;
- if (mBiometricService == null) {
- mBiometricService = IBiometricService.Stub.asInterface(
- ServiceManager.getService(Context.BIOMETRIC_SERVICE));
- }
- try {
- mBiometricService.onReadyForAuthentication(client.getCookie());
- } catch (RemoteException e) {
- Slog.e(getTag(), "Remote exception", e);
- }
- return;
- }
- }
-
- // We are not a BiometricPrompt client, start the client immediately
- mCurrentClient = newClient;
- startCurrentClient(mCurrentClient.getCookie());
- }
- }
-
- protected void startCurrentClient(int cookie) {
- if (mCurrentClient == null) {
- Slog.e(getTag(), "Trying to start null client!");
- return;
- }
-
- if (DEBUG) Slog.v(getTag(), "Starting client "
- + mCurrentClient.getClass().getSimpleName()
- + "(" + mCurrentClient.getOwnerString() + ")"
- + " targetUserId: " + mCurrentClient.getTargetUserId()
- + " currentUserId: " + mCurrentUserId
- + " cookie: " + cookie + "/" + mCurrentClient.getCookie());
-
- if (cookie != mCurrentClient.getCookie()) {
- Slog.e(getTag(), "Mismatched cookie");
- return;
- }
-
- final T daemon = mCurrentClient.getFreshDaemon();
- if (daemon == null) {
- Slog.e(getTag(), "Daemon null, unable to start: "
- + mCurrentClient.getClass().getSimpleName());
- mCurrentClient.unableToStart();
- mCurrentClient = null;
- return;
- }
-
- mCurrentClient.start(mClientFinishCallback);
- notifyClientActiveCallbacks(true);
- }
-
- protected void removeClient(ClientMonitor<?> client) {
- if (client != null) {
- client.destroy();
- if (client != mCurrentClient && mCurrentClient != null) {
- Slog.w(getTag(), "Unexpected client: " + client.getOwnerString() + "expected: "
- + mCurrentClient.getOwnerString());
- }
- }
- if (mCurrentClient != null) {
- if (DEBUG) Slog.v(getTag(), "Done with client: "
- + mCurrentClient.getClass().getSimpleName()
- + "(" + mCurrentClient.getOwnerString() + ")");
- mCurrentClient = null;
- }
- if (mPendingClient == null) {
- notifyClientActiveCallbacks(false);
- }
- }
-
- /**
- * Populates existing authenticator ids. To be used only during the start of the service.
- */
- protected void loadAuthenticatorIds() {
- // This operation can be expensive, so keep track of the elapsed time. Might need to move to
- // background if it takes too long.
- long t = System.currentTimeMillis();
- mAuthenticatorIds.clear();
- for (UserInfo user : UserManager.get(getContext()).getUsers(true /* excludeDying */)) {
- int userId = user.id;
- if (!mAuthenticatorIds.containsKey(userId)) {
- updateActiveGroup(userId);
- }
- }
-
- t = System.currentTimeMillis() - t;
- if (t > 1000) {
- Slog.w(getTag(), "loadAuthenticatorIds() taking too long: " + t + "ms");
- }
- }
-
- protected boolean isRestricted() {
- // Only give privileged apps (like Settings) access to biometric info
- final boolean restricted = !hasPermission(getManageBiometricPermission());
- return restricted;
- }
-
- protected boolean hasPermission(String permission) {
- return getContext().checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
- }
-
- protected void checkPermission(String permission) {
- getContext().enforceCallingOrSelfPermission(permission,
- "Must have " + permission + " permission.");
- }
-
- /**
- * @return authenticator id for the calling user
- */
- protected long getAuthenticatorId(int callingUserId) {
- return mAuthenticatorIds.getOrDefault(callingUserId, 0L);
- }
-
- /**
- * This method should be called upon connection to the daemon, and when user switches.
- */
- protected abstract void doTemplateCleanupForUser(int userId);
-
- /**
- * This method is called when the user switches. Implementations should probably notify the
- * HAL.
- */
- protected void handleUserSwitching(int userId) {
- if (getCurrentClient() instanceof InternalCleanupClient) {
- Slog.w(getTag(), "User switched while performing cleanup");
- }
- updateActiveGroup(userId);
- doTemplateCleanupForUser(userId);
- }
-
- private void listenForUserSwitches() {
- try {
- ActivityManager.getService().registerUserSwitchObserver(
- new SynchronousUserSwitchObserver() {
- @Override
- public void onUserSwitching(int newUserId) {
- mHandler.obtainMessage(MSG_USER_SWITCHING, newUserId, 0 /* unused */)
- .sendToTarget();
- }
- }, getTag());
- } catch (RemoteException e) {
- Slog.w(getTag(), "Failed to listen for user switching event" ,e);
- }
- }
-}
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 8cabdf52314c..8b27781940ac 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitor.java
@@ -34,7 +34,7 @@ import java.util.NoSuchElementException;
public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinder.DeathRecipient {
private static final String TAG = "Biometrics/ClientMonitor";
- protected static final boolean DEBUG = BiometricServiceBase.DEBUG;
+ protected static final boolean DEBUG = true;
// Counter used to distinguish between ClientMonitor instances to help debugging.
private static int sCount = 0;
diff --git a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
index ad14531a9001..3cef6667b644 100644
--- a/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
+++ b/services/core/java/com/android/server/biometrics/sensors/ClientMonitorCallbackConverter.java
@@ -101,6 +101,15 @@ public final class ClientMonitorCallbackConverter {
// The following only apply to IFingerprintServiceReceiver and IFaceServiceReceiver
+ public void onDetected(int sensorId, int userId, boolean isStrongBiometric)
+ throws RemoteException {
+ if (mFaceServiceReceiver != null) {
+ mFaceServiceReceiver.onFaceDetected(sensorId, userId, isStrongBiometric);
+ } else if (mFingerprintServiceReceiver != null) {
+ mFingerprintServiceReceiver.onFingerprintDetected(sensorId, userId, isStrongBiometric);
+ }
+ }
+
void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining)
throws RemoteException {
if (mFaceServiceReceiver != null) {
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 a3d96778d177..add5829c1342 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -35,11 +35,15 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
protected final byte[] mHardwareAuthToken;
protected final int mTimeoutSec;
- private final BiometricUtils mBiometricUtils;
+ protected final BiometricUtils mBiometricUtils;
private final boolean mShouldVibrate;
private long mEnrollmentStartTimeMs;
- private boolean mAlreadyCancelled;
+
+ /**
+ * @return true if the user has already enrolled the maximum number of templates.
+ */
+ protected abstract boolean hasReachedEnrollmentLimit();
public EnrollClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@@ -82,19 +86,14 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
public void start(@NonNull FinishCallback finishCallback) {
super.start(finishCallback);
- mEnrollmentStartTimeMs = System.currentTimeMillis();
- startHalOperation();
- }
-
- @Override
- public void cancel() {
- if (mAlreadyCancelled) {
- Slog.w(TAG, "stopEnroll: already cancelled!");
+ if (hasReachedEnrollmentLimit()) {
+ Slog.e(TAG, "Reached enrollment limit");
+ finishCallback.onClientFinished(this, false /* success */);
return;
}
- stopHalOperation();
- mAlreadyCancelled = true;
+ mEnrollmentStartTimeMs = System.currentTimeMillis();
+ startHalOperation();
}
/**
diff --git a/services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java b/services/core/java/com/android/server/biometrics/sensors/LockoutResetDispatcher.java
index 22c10b350e7d..f4997d4abe24 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LockoutResetTracker.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LockoutResetDispatcher.java
@@ -32,7 +32,7 @@ import java.util.ArrayList;
* ends. This class keeps track of all client callbacks. Individual sensors should notify this
* when lockout for a specific sensor has been reset.
*/
-public class LockoutResetTracker implements IBinder.DeathRecipient {
+public class LockoutResetDispatcher implements IBinder.DeathRecipient {
private static final String TAG = "LockoutResetTracker";
@@ -79,7 +79,7 @@ public class LockoutResetTracker implements IBinder.DeathRecipient {
}
}
- public LockoutResetTracker(Context context) {
+ public LockoutResetDispatcher(Context context) {
mContext = context;
mClientCallbacks = new ArrayList<>();
}
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 a7c63f75d707..1a4216f9d43c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/LoggableMonitor.java
@@ -39,10 +39,6 @@ public abstract class LoggableMonitor {
private final int mStatsClient;
private long mFirstAcquireTimeMs;
- protected long getFirstAcquireTimeMs() {
- return mFirstAcquireTimeMs;
- }
-
/**
* Only valid for AuthenticationClient.
* @return true if the client is authenticating for a crypto operation.
@@ -62,6 +58,12 @@ public abstract class LoggableMonitor {
mStatsClient = statsClient;
}
+ private boolean isAnyFieldUnknown() {
+ return mStatsModality == BiometricsProtoEnums.MODALITY_UNKNOWN
+ || mStatsAction == BiometricsProtoEnums.ACTION_UNKNOWN
+ || mStatsClient == BiometricsProtoEnums.CLIENT_UNKNOWN;
+ }
+
protected final void logOnAcquired(Context context, int acquiredInfo, int vendorCode,
int targetUserId) {
@@ -86,6 +88,11 @@ public abstract class LoggableMonitor {
+ ", AcquiredInfo: " + acquiredInfo
+ ", VendorCode: " + vendorCode);
}
+
+ if (isAnyFieldUnknown()) {
+ return;
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ACQUIRED,
mStatsModality,
targetUserId,
@@ -114,6 +121,11 @@ public abstract class LoggableMonitor {
} else {
Slog.v(TAG, "Error latency: " + latency);
}
+
+ if (isAnyFieldUnknown()) {
+ return;
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ERROR_OCCURRED,
mStatsModality,
targetUserId,
@@ -157,6 +169,10 @@ public abstract class LoggableMonitor {
Slog.v(TAG, "Authentication latency: " + latency);
}
+ if (isAnyFieldUnknown()) {
+ return;
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_AUTHENTICATED,
mStatsModality,
targetUserId,
@@ -179,6 +195,10 @@ public abstract class LoggableMonitor {
Slog.v(TAG, "Enroll latency: " + latency);
}
+ if (isAnyFieldUnknown()) {
+ return;
+ }
+
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_ENROLLED,
mStatsModality,
targetUserId,
diff --git a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
index 9fdba4b6d1bc..42b22b0fb519 100644
--- a/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
+++ b/services/core/java/com/android/server/biometrics/sensors/PerformanceTracker.java
@@ -65,7 +65,7 @@ public class PerformanceTracker {
}
}
- void incrementAuthForUser(int userId, boolean accepted) {
+ public void incrementAuthForUser(int userId, boolean accepted) {
createUserEntryIfNecessary(userId);
if (accepted) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
new file mode 100644
index 000000000000..7f2b18b9edf5
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/Face10.java
@@ -0,0 +1,657 @@
+/*
+ * 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.biometrics.sensors.face;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.NotificationManager;
+import android.app.SynchronousUserSwitchObserver;
+import android.app.UserSwitchObserver;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
+import android.hardware.face.Face;
+import android.hardware.face.IFaceServiceReceiver;
+import android.hardware.face.FaceSensorProperties;
+import android.os.Build;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IHwBinder;
+import android.os.Looper;
+import android.os.NativeHandle;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.biometrics.Utils;
+import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.BiometricScheduler;
+import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.EnumerateConsumer;
+import com.android.server.biometrics.sensors.Interruptable;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.LockoutTracker;
+import com.android.server.biometrics.sensors.PerformanceTracker;
+import com.android.server.biometrics.sensors.RemovalConsumer;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintUpdateActiveUserClient;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or
+ * its extended minor versions.
+ */
+class Face10 implements IHwBinder.DeathRecipient {
+
+ private static final String TAG = "Face10";
+ private static final int ENROLL_TIMEOUT_SEC = 75;
+ static final String NOTIFICATION_TAG = "FaceService";
+ static final int NOTIFICATION_ID = 1;
+
+ @NonNull private final FaceSensorProperties mFaceSensorProperties;
+ @NonNull private final Context mContext;
+ @NonNull private final BiometricScheduler mScheduler;
+ @NonNull private final Handler mHandler;
+ @NonNull private final ClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
+ @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
+ @NonNull private final LockoutHalImpl mLockoutTracker;
+ @NonNull private final UsageStats mUsageStats;
+ @NonNull private NotificationManager mNotificationManager;
+ private final int mSensorId;
+ @NonNull private final Map<Integer, Long> mAuthenticatorIds;
+
+ @Nullable private IBiometricsFace mDaemon;
+ private int mCurrentUserId = UserHandle.USER_NULL;
+
+ private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() {
+ @Override
+ public void onUserSwitching(int newUserId) {
+ scheduleInternalCleanup(newUserId);
+ }
+ };
+
+ private final IBiometricsFaceClientCallback mDaemonCallback =
+ new IBiometricsFaceClientCallback.Stub() {
+ @Override
+ public void onEnrollResult(long deviceId, int faceId, int userId, int remaining) {
+ mHandler.post(() -> {
+ final CharSequence name = FaceUtils.getInstance()
+ .getUniqueName(mContext, userId);
+ final Face face = new Face(name, faceId, deviceId);
+
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof FaceEnrollClient)) {
+ Slog.e(TAG, "onEnrollResult for non-enroll client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final FaceEnrollClient enrollClient = (FaceEnrollClient) client;
+ enrollClient.onEnrollResult(face, remaining);
+ });
+ }
+
+ @Override
+ public void onAuthenticated(long deviceId, int faceId, int userId, ArrayList<Byte> token) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AuthenticationConsumer)) {
+ Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AuthenticationConsumer authenticationConsumer =
+ (AuthenticationConsumer) client;
+ final boolean authenticated = faceId != 0;
+ final Face face = new Face("", faceId, deviceId);
+ authenticationConsumer.onAuthenticated(face, authenticated, token);
+ });
+ }
+
+ @Override
+ public void onAcquired(long deviceId, int userId, int acquiredInfo, int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof AcquisitionClient)) {
+ Slog.e(TAG, "onAcquired for non-acquire client: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final AcquisitionClient<?> acquisitionClient = (AcquisitionClient<?>) client;
+ acquisitionClient.onAcquired(acquiredInfo, vendorCode);
+ });
+ }
+
+ @Override
+ public void onError(long deviceId, int userId, int error, int vendorCode) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ Slog.d(TAG, "handleError"
+ + ", client: " + (client != null ? client.getOwnerString() : null)
+ + ", error: " + error
+ + ", vendorCode: " + vendorCode);
+ if (!(client instanceof Interruptable)) {
+ Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(client));
+ return;
+ }
+
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(error, vendorCode);
+
+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
+ Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE");
+ mDaemon = null;
+ mCurrentUserId = UserHandle.USER_NULL;
+ }
+ });
+ }
+
+ @Override
+ public void onRemoved(long deviceId, ArrayList<Integer> removed, int userId) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof RemovalConsumer)) {
+ Slog.e(TAG, "onRemoved for non-removal consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final RemovalConsumer removalConsumer = (RemovalConsumer) client;
+
+ if (!removed.isEmpty()) {
+ // Convert to old fingerprint-like behavior, where remove() receives one removal
+ // at a time. This way, remove can share some more common code.
+ for (int i = 0; i < removed.size(); i++) {
+ final int id = removed.get(i);
+ final Face face = new Face("", id, deviceId);
+ final int remaining = removed.size() - i - 1;
+ Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining);
+ removalConsumer.onRemoved(face, remaining);
+ }
+ } else {
+ final Face face = new Face("", 0 /* identifier */, deviceId);
+ removalConsumer.onRemoved(face, 0 /* remaining */);
+ }
+
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
+ });
+ }
+
+ @Override
+ public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId) {
+ mHandler.post(() -> {
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (!(client instanceof EnumerateConsumer)) {
+ Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
+ + Utils.getClientName(client));
+ return;
+ }
+
+ final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client;
+
+ if (!faceIds.isEmpty()) {
+ // Convert to old fingerprint-like behavior, where enumerate() receives one
+ // template at a time. This way, enumerate can share some more common code.
+ for (int i = 0; i < faceIds.size(); i++) {
+ final Face face = new Face("", faceIds.get(i), deviceId);
+ enumerateConsumer.onEnumerationResult(face, faceIds.size() - i - 1);
+ }
+ } else {
+ // For face, the HIDL contract is to receive an empty list when there are no
+ // templates enrolled. Send a null identifier since we don't consume them
+ // anywhere, and send remaining == 0 so this code can be shared with
+ // Fingerprint@2.1
+ enumerateConsumer.onEnumerationResult(null /* identifier */, 0);
+ }
+ });
+ }
+
+ @Override
+ public void onLockoutChanged(long duration) {
+ mHandler.post(() -> {
+ Slog.d(TAG, "onLockoutChanged: " + duration);
+ final @LockoutTracker.LockoutMode int lockoutMode;
+ if (duration == 0) {
+ lockoutMode = LockoutTracker.LOCKOUT_NONE;
+ } else if (duration == -1 || duration == Long.MAX_VALUE) {
+ lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
+ } else {
+ lockoutMode = LockoutTracker.LOCKOUT_TIMED;
+ }
+
+ mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
+
+ if (duration == 0) {
+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId);
+ }
+ });
+ }
+ };
+
+ Face10(@NonNull Context context, int sensorId,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) {
+ mFaceSensorProperties = new FaceSensorProperties(false /* supportsFaceDetect */);
+ mContext = context;
+ mSensorId = sensorId;
+ mScheduler = new BiometricScheduler(TAG, null /* gestureAvailabilityTracker */);
+ mHandler = new Handler(Looper.getMainLooper());
+ mUsageStats = new UsageStats(context);
+ mAuthenticatorIds = new HashMap<>();
+ mLazyDaemon = Face10.this::getDaemon;
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
+ mLockoutTracker = new LockoutHalImpl();
+ mLockoutResetDispatcher = lockoutResetDispatcher;
+
+ try {
+ ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to register user switch observer");
+ }
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ Slog.e(TAG, "HAL died");
+ mHandler.post(() -> {
+ PerformanceTracker.getInstanceForSensorId(mSensorId)
+ .incrementHALDeathCount();
+ mDaemon = null;
+ mCurrentUserId = UserHandle.USER_NULL;
+
+ final ClientMonitor<?> client = mScheduler.getCurrentClient();
+ if (client instanceof Interruptable) {
+ Slog.e(TAG, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
+ final Interruptable interruptable = (Interruptable) client;
+ interruptable.onError(BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+
+ mScheduler.recordCrashState();
+
+ FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+ BiometricsProtoEnums.MODALITY_FACE,
+ BiometricsProtoEnums.ISSUE_HAL_DEATH);
+ }
+ });
+ }
+
+ private synchronized IBiometricsFace getDaemon() {
+ if (mDaemon != null) {
+ return mDaemon;
+ }
+
+ Slog.d(TAG, "Daemon was null, reconnecting, current operation: "
+ + mScheduler.getCurrentClient());
+
+ try {
+ mDaemon = IBiometricsFace.getService();
+ } catch (java.util.NoSuchElementException e) {
+ // Service doesn't exist or cannot be opened.
+ Slog.w(TAG, "NoSuchElementException", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get face HAL", e);
+ }
+
+ if (mDaemon == null) {
+ Slog.w(TAG, "Face HAL not available");
+ return null;
+ }
+
+ mDaemon.asBinder().linkToDeath(this, 0 /* flags */);
+
+ // HAL ID for these HIDL versions are only used to determine if callbacks have been
+ // successfully set.
+ long halId = 0;
+ try {
+ halId = mDaemon.setCallback(mDaemonCallback).value;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set callback for face HAL", e);
+ mDaemon = null;
+ }
+
+ Slog.d(TAG, "Face HAL ready, HAL ID: " + halId);
+ if (halId != 0) {
+ scheduleLoadAuthenticatorIds();
+ scheduleInternalCleanup(ActivityManager.getCurrentUser());
+ } else {
+ Slog.e(TAG, "Unable to set callback");
+ mDaemon = null;
+ }
+
+ return mDaemon;
+ }
+
+ @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
+ return mLockoutTracker.getLockoutModeForUser(userId);
+ }
+
+ private void scheduleLoadAuthenticatorIds() {
+ // Note that this can be performed on the scheduler (as opposed to being done immediately
+ // when the HAL is (re)loaded, since
+ // 1) If this is truly the first time it's being performed (e.g. system has just started),
+ // this will be run very early and way before any applications need to generate keys.
+ // 2) If this is being performed to refresh the authenticatorIds (e.g. HAL crashed and has
+ // just been reloaded), the framework already has a cache of the authenticatorIds. This
+ // is safe because authenticatorIds only change when A) new template has been enrolled,
+ // or B) all templates are removed.
+ mHandler.post(() -> {
+ for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+ final int targetUserId = user.id;
+ if (!mAuthenticatorIds.containsKey(targetUserId)) {
+ scheduleUpdateActiveUserWithoutHandler(targetUserId);
+ }
+ }
+ });
+ }
+
+ /**
+ * Schedules the {@link FingerprintUpdateActiveUserClient} without posting the work onto the
+ * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser"
+ * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule
+ * this operation on the same lambda/runnable as those operations so that the ordering is
+ * correct.
+ */
+ private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
+ final boolean hasEnrolled = !getEnrolledFaces(targetUserId).isEmpty();
+ final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
+ mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId,
+ hasEnrolled, mAuthenticatorIds);
+ mScheduler.scheduleClientMonitor(client, (clientMonitor, success) -> {
+ if (success) {
+ mCurrentUserId = targetUserId;
+ }
+ });
+ }
+
+ void scheduleResetLockout(int userId, @NonNull byte[] hardwareAuthToken) {
+ mHandler.post(() -> {
+ if (getEnrolledFaces(userId).isEmpty()) {
+ Slog.w(TAG, "Ignoring lockout reset, no templates enrolled for user: " + userId);
+ return;
+ }
+
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final FaceResetLockoutClient client = new FaceResetLockoutClient(mContext,
+ mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId,
+ hardwareAuthToken);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void scheduleSetFeature(@NonNull IBinder token, int userId, int feature, boolean enabled,
+ @NonNull byte[] hardwareAuthToken, @NonNull IFaceServiceReceiver receiver,
+ @NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final List<Face> faces = getEnrolledFaces(userId);
+ if (faces.isEmpty()) {
+ Slog.w(TAG, "Ignoring setFeature, no templates enrolled for user: " + userId);
+ return;
+ }
+
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final int faceId = faces.get(0).getBiometricId();
+ final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext,
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
+ opPackageName, mSensorId, feature, enabled, hardwareAuthToken, faceId);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void scheduleGetFeature(@NonNull IBinder token, int userId, int feature,
+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final List<Face> faces = getEnrolledFaces(userId);
+ if (faces.isEmpty()) {
+ Slog.w(TAG, "Ignoring getFeature, no templates enrolled for user: " + userId);
+ return;
+ }
+
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final int faceId = faces.get(0).getBiometricId();
+ final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext,
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
+ opPackageName, mSensorId, feature, faceId);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void scheduleGenerateChallenge(@NonNull IBinder token, @NonNull IFaceServiceReceiver receiver,
+ @NonNull String opPackageName) {
+ mHandler.post(() -> {
+ final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName,
+ mSensorId);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void scheduleRevokeChallenge(@NonNull IBinder token, @NonNull String owner) {
+ mHandler.post(() -> {
+ final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
+ mLazyDaemon, token, owner, mSensorId);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void scheduleEnroll(@NonNull IBinder token, @NonNull byte[] hardwareAuthToken, int userId,
+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName,
+ @NonNull int[] disabledFeatures, @Nullable NativeHandle surfaceHandle) {
+ mHandler.post(() -> {
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+
+ final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token,
+ new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
+ opPackageName, FaceUtils.getInstance(), disabledFeatures, ENROLL_TIMEOUT_SEC,
+ surfaceHandle, mSensorId);
+
+ mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> {
+ if (success) {
+ // Update authenticatorIds
+ scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId());
+ }
+ }));
+ });
+ }
+
+ void cancelEnrollment(@NonNull IBinder token) {
+ mHandler.post(() -> {
+ mScheduler.cancelEnrollment(token);
+ });
+ }
+
+ void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId, int cookie,
+ @NonNull ClientMonitorCallbackConverter receiver, @NonNull String opPackageName,
+ boolean restricted, int statsClient) {
+ mHandler.post(() -> {
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId);
+ final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
+ mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
+ cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
+ statsClient, mLockoutTracker, mUsageStats);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ void startPreparedClient(int cookie) {
+ mHandler.post(() -> {
+ mScheduler.startPreparedClient(cookie);
+ });
+ }
+
+ void cancelAuthentication(@NonNull IBinder token) {
+ mHandler.post(() -> {
+ mScheduler.cancelAuthentication(token);
+ });
+ }
+
+ void scheduleRemove(@NonNull IBinder token, int faceId, int userId,
+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
+ mHandler.post(() -> {
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token,
+ new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
+ FaceUtils.getInstance(), mSensorId, mAuthenticatorIds);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ private void scheduleInternalCleanup(int userId) {
+ mHandler.post(() -> {
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final List<Face> enrolledList = getEnrolledFaces(userId);
+ final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext,
+ mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, enrolledList,
+ FaceUtils.getInstance(), mAuthenticatorIds);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
+ boolean isHardwareDetected() {
+ final IBiometricsFace daemon = getDaemon();
+ return daemon != null;
+ }
+
+ FaceSensorProperties getFaceSensorProperties() {
+ return mFaceSensorProperties;
+ }
+
+ List<Face> getEnrolledFaces(int userId) {
+ return FaceUtils.getInstance().getBiometricsForUser(mContext, userId);
+ }
+
+ long getAuthenticatorId(int userId) {
+ return mAuthenticatorIds.get(userId);
+ }
+
+ public void dump(@NonNull PrintWriter pw) {
+ PerformanceTracker performanceTracker =
+ PerformanceTracker.getInstanceForSensorId(mSensorId);
+
+ JSONObject dump = new JSONObject();
+ try {
+ dump.put("service", "Face Manager");
+
+ JSONArray sets = new JSONArray();
+ for (UserInfo user : UserManager.get(mContext).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final int N = FaceUtils.getInstance().getBiometricsForUser(mContext, userId).size();
+ JSONObject set = new JSONObject();
+ set.put("id", userId);
+ set.put("count", N);
+ set.put("accept", performanceTracker.getAcceptForUser(userId));
+ set.put("reject", performanceTracker.getRejectForUser(userId));
+ set.put("acquire", performanceTracker.getAcquireForUser(userId));
+ set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
+ set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
+ // cryptoStats measures statistics about secure face transactions
+ // (e.g. to unlock password storage, make secure purchases, etc.)
+ set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
+ set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
+ set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
+ sets.put(set);
+ }
+
+ dump.put("prints", sets);
+ } catch (JSONException e) {
+ Slog.e(TAG, "dump formatting failure", e);
+ }
+ pw.println(dump);
+ pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
+
+ mUsageStats.print(pw);
+ }
+
+ public void dumpHal(@NonNull FileDescriptor fd, @NonNull String[] args) {
+ // WARNING: CDD restricts image data from leaving TEE unencrypted on
+ // production devices:
+ // [C-1-10] MUST not allow unencrypted access to identifiable biometric
+ // data or any data derived from it (such as embeddings) to the
+ // Application Processor outside the context of the TEE.
+ // As such, this API should only be enabled for testing purposes on
+ // engineering and userdebug builds. All modules in the software stack
+ // MUST enforce final build products do NOT have this functionality.
+ // Additionally, the following check MUST NOT be removed.
+ if (!(Build.IS_ENG || Build.IS_USERDEBUG)) {
+ return;
+ }
+
+ // Additionally, this flag allows turning off face for a device
+ // (either permanently through the build or on an individual device).
+ if (SystemProperties.getBoolean("ro.face.disable_debug_data", false)
+ || SystemProperties.getBoolean("persist.face.disable_debug_data", false)) {
+ return;
+ }
+
+ // The debug method takes two file descriptors. The first is for text
+ // output, which we will drop. The second is for binary data, which
+ // will be the protobuf data.
+ final IBiometricsFace daemon = getDaemon();
+ if (daemon != null) {
+ FileOutputStream devnull = null;
+ try {
+ devnull = new FileOutputStream("/dev/null");
+ final NativeHandle handle = new NativeHandle(
+ new FileDescriptor[] { devnull.getFD(), fd },
+ new int[0], false);
+ daemon.debug(handle, new ArrayList<String>(Arrays.asList(args)));
+ } catch (IOException | RemoteException ex) {
+ Slog.d(TAG, "error while reading face debugging data", ex);
+ } finally {
+ if (devnull != null) {
+ try {
+ devnull.close();
+ } catch (IOException ex) {
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
index 118cadc9f9fa..21bda74bc6b9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticationClient.java
@@ -21,7 +21,6 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
-import android.app.TaskStackListener;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -67,11 +66,10 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient,
- @NonNull TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker, @NonNull UsageStats usageStats) {
super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
owner, cookie, requireConfirmation, sensorId, isStrongBiometric,
- BiometricsProtoEnums.MODALITY_FACE, statsClient, taskStackListener,
+ BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutTracker);
mNotificationManager = context.getSystemService(NotificationManager.class);
mUsageStats = usageStats;
@@ -221,8 +219,8 @@ class FaceAuthenticationClient extends AuthenticationClient<IBiometricsFace> {
.build();
mNotificationManager.createNotificationChannel(channel);
- mNotificationManager.notifyAsUser(FaceService.NOTIFICATION_TAG,
- FaceService.NOTIFICATION_ID, notification,
+ mNotificationManager.notifyAsUser(Face10.NOTIFICATION_TAG,
+ Face10.NOTIFICATION_ID, notification,
UserHandle.CURRENT);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
index 4f9f46aff4c0..52a822675c2f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceEnrollClient.java
@@ -68,6 +68,19 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
}
@Override
+ protected boolean hasReachedEnrollmentLimit() {
+ final int limit = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_faceMaxTemplatesPerUser);
+ final int enrolled = mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId())
+ .size();
+ if (enrolled >= limit) {
+ Slog.w(TAG, "Too many faces registered, user: " + getTargetUserId());
+ return true;
+ }
+ return false;
+ }
+
+ @Override
public void onAcquired(int acquireInfo, int vendorCode) {
final boolean shouldSend;
if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 7a051921f403..610faa04ca3b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -16,64 +16,34 @@
package com.android.server.biometrics.sensors.face;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
-import android.app.ActivityManager;
-import android.app.NotificationManager;
+import android.annotation.NonNull;
import android.content.Context;
-import android.content.pm.UserInfo;
-import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricServiceLockoutResetCallback;
-import android.hardware.biometrics.face.V1_0.IBiometricsFace;
-import android.hardware.biometrics.face.V1_0.IBiometricsFaceClientCallback;
import android.hardware.face.Face;
import android.hardware.face.IFaceService;
import android.hardware.face.IFaceServiceReceiver;
+import android.hardware.face.FaceSensorProperties;
import android.os.Binder;
-import android.os.Build;
-import android.os.Environment;
import android.os.IBinder;
import android.os.NativeHandle;
-import android.os.RemoteException;
-import android.os.SELinux;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
import android.util.Slog;
import android.view.Surface;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
-import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.sensors.AuthenticationClient;
-import com.android.server.biometrics.sensors.BiometricServiceBase;
-import com.android.server.biometrics.sensors.BiometricUtils;
-import com.android.server.biometrics.sensors.ClientMonitor;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.SystemService;
+import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
-import com.android.server.biometrics.sensors.EnrollClient;
-import com.android.server.biometrics.sensors.GenerateChallengeClient;
-import com.android.server.biometrics.sensors.LockoutResetTracker;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.PerformanceTracker;
-import com.android.server.biometrics.sensors.RemovalClient;
-import com.android.server.biometrics.sensors.RevokeChallengeClient;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -82,177 +52,150 @@ import java.util.List;
* The service is responsible for maintaining a list of clients and dispatching all
* face-related events.
*/
-public class FaceService extends BiometricServiceBase<IBiometricsFace> {
+public class FaceService extends SystemService {
protected static final String TAG = "FaceService";
- private static final boolean DEBUG = true;
- private static final String FACE_DATA_DIR = "facedata";
- private static final String ACTION_LOCKOUT_RESET =
- "com.android.server.biometrics.face.ACTION_LOCKOUT_RESET";
-
-
- static final String NOTIFICATION_TAG = "FaceService";
- static final int NOTIFICATION_ID = 1;
- private final LockoutResetTracker mLockoutResetTracker;
- private final ClientMonitor.LazyDaemon<IBiometricsFace> mLazyDaemon;
+ private Face10 mFace10;
+ private final LockoutResetDispatcher mLockoutResetDispatcher;
+ private final LockPatternUtils mLockPatternUtils;
/**
* Receives the incoming binder calls from FaceManager.
*/
private final class FaceServiceWrapper extends IFaceService.Stub {
- private static final int ENROLL_TIMEOUT_SEC = 75;
-
- /**
- * The following methods contain common code which is shared in biometrics/common.
- */
-
@Override // Binder call
public void generateChallenge(IBinder token, IFaceServiceReceiver receiver,
String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
-
- final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(getContext(),
- mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), opPackageName,
- getSensorId());
- generateChallengeInternal(client);
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ mFace10.scheduleGenerateChallenge(token, receiver, opPackageName);
}
@Override // Binder call
public void revokeChallenge(IBinder token, String owner) {
- checkPermission(MANAGE_BIOMETRIC);
-
- final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(getContext(),
- mLazyDaemon, token, owner, getSensorId());
-
- // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
- if (getCurrentClient() == null) {
- // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke
- // the challenge right away.
- revokeChallengeInternal(client);
- } else {
- // postpone revoking the challenge until we finish processing the current HIDL
- // call.
- mPendingRevokeChallenge = client;
- }
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ mFace10.scheduleRevokeChallenge(token, owner);
}
@Override // Binder call
public void enroll(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures, Surface surface) {
- checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId);
-
- mHandler.post(() -> {
- mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
- UserHandle.CURRENT);
- });
-
- final FaceEnrollClient client = new FaceEnrollClient(getContext(), mLazyDaemon, token,
- new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
- opPackageName, getBiometricUtils(), disabledFeatures, ENROLL_TIMEOUT_SEC,
- convertSurfaceToNativeHandle(surface), getSensorId());
-
- enrollInternal(client, userId);
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ mFace10.scheduleEnroll(token, hardwareAuthToken, userId, receiver, opPackageName,
+ disabledFeatures, convertSurfaceToNativeHandle(surface));
}
@Override // Binder call
public void enrollRemotely(int userId, final IBinder token, final byte[] hardwareAuthToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures) {
- checkPermission(MANAGE_BIOMETRIC);
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
// TODO(b/145027036): Implement this.
}
@Override // Binder call
public void cancelEnrollment(final IBinder token) {
- checkPermission(MANAGE_BIOMETRIC);
- cancelEnrollmentInternal(token);
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ mFace10.cancelEnrollment(token);
}
@Override // Binder call
- public void authenticate(final IBinder token, final long opId, int userId,
+ public void authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- updateActiveGroup(userId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+
+ // TODO(b/152413782): If the sensor supports face detect and the device is encrypted or
+ // lockdown, something wrong happened. See similar path in FingerprintService.
- final boolean restricted = isRestricted();
- final int statsClient = isKeyguard(opPackageName) ? BiometricsProtoEnums.CLIENT_KEYGUARD
+ final boolean restricted = false; // Face APIs are private
+ final int statsClient = Utils.isKeyguard(getContext(), opPackageName)
+ ? BiometricsProtoEnums.CLIENT_KEYGUARD
: BiometricsProtoEnums.CLIENT_UNKNOWN;
- final FaceAuthenticationClient client = new FaceAuthenticationClient(getContext(),
- mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, opId,
- restricted, opPackageName, 0 /* cookie */, false /* requireConfirmation */,
- getSensorId(), isStrongBiometric(), statsClient, mTaskStackListener,
- mLockoutTracker, mUsageStats);
- authenticateInternal(client, opPackageName);
+ mFace10.scheduleAuthenticate(token, operationId, userId, 0 /* cookie */,
+ new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
+ statsClient);
}
@Override // Binder call
- public void prepareForAuthentication(boolean requireConfirmation, IBinder token, long opId,
- int userId, IBiometricSensorReceiver sensorReceiver,
+ public void detectFace(final IBinder token, final int userId,
+ final IFaceServiceReceiver receiver, final String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (!Utils.isKeyguard(getContext(), opPackageName)) {
+ Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName);
+ return;
+ }
+
+ if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
+ // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
+ // ever be invoked when the user is encrypted or lockdown.
+ Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown");
+ return;
+ }
+
+ // TODO(b/152413782): Implement this once it's supported in the HAL
+ }
+
+ @Override // Binder call
+ public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
+ long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
String opPackageName, int cookie, int callingUid, int callingPid,
int callingUserId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- updateActiveGroup(userId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final boolean restricted = true; // BiometricPrompt is always restricted
- final FaceAuthenticationClient client = new FaceAuthenticationClient(getContext(),
- mLazyDaemon, token, new ClientMonitorCallbackConverter(sensorReceiver), userId,
- opId, restricted, opPackageName, cookie, requireConfirmation, getSensorId(),
- isStrongBiometric(), BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
- mTaskStackListener, mLockoutTracker, mUsageStats);
- authenticateInternal(client, opPackageName);
+ mFace10.scheduleAuthenticate(token, operationId, userId, cookie,
+ new ClientMonitorCallbackConverter(sensorReceiver), opPackageName,
+ restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT);
}
@Override // Binder call
public void startPreparedClient(int cookie) {
- checkPermission(MANAGE_BIOMETRIC);
- startCurrentClient(cookie);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.startPreparedClient(cookie);
}
@Override // Binder call
public void cancelAuthentication(final IBinder token, final String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- cancelAuthenticationInternal(token, opPackageName, true /* fromClient */);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.cancelAuthentication(token);
+ }
+
+ @Override // Binder call
+ public void cancelFaceDetect(final IBinder token, final String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (!Utils.isKeyguard(getContext(), opPackageName)) {
+ Slog.w(TAG, "cancelFaceDetect called from non-sysui package: "
+ + opPackageName);
+ return;
+ }
+
+ // TODO(b/152413782): Implement this once it's supported in the HAL
}
@Override // Binder call
public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
int callingUid, int callingPid, int callingUserId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- // Cancellation is from system server in this case.
- cancelAuthenticationInternal(token, opPackageName, false /* fromClient */);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.cancelAuthentication(token);
}
@Override // Binder call
public void remove(final IBinder token, final int faceId, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
- updateActiveGroup(userId);
-
- if (token == null) {
- Slog.w(TAG, "remove(): token is null");
- return;
- }
-
- final FaceRemovalClient client = new FaceRemovalClient(getContext(), mLazyDaemon, token,
- new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName,
- getBiometricUtils(), getSensorId(), mAuthenticatorIds);
- removeInternal(client);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.scheduleRemove(token, faceId, userId, receiver, opPackageName);
}
@Override
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
final String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- mHandler.post(() -> {
- mLockoutResetTracker.addCallback(callback, opPackageName);
- });
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mLockoutResetDispatcher.addCallback(callback, opPackageName);
}
@Override // Binder call
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
}
@@ -260,28 +203,25 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
final long ident = Binder.clearCallingIdentity();
try {
if (args.length > 1 && "--hal".equals(args[0])) {
- dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass()));
+ mFace10.dumpHal(fd, Arrays.copyOfRange(args, 1, args.length, args.getClass()));
} else {
- dumpInternal(pw);
+ mFace10.dump(pw);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
- /**
- * The following methods don't use any common code from BiometricService
- */
-
- // TODO: refactor out common code here
@Override // Binder call
public boolean isHardwareDetected(String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
-
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (mFace10 == null) {
+ Slog.wtf(TAG, "No HAL, caller: " + opPackageName);
+ return false;
+ }
final long token = Binder.clearCallingIdentity();
try {
- IBiometricsFace daemon = getFaceDaemon();
- return daemon != null;
+ return mFace10.isHardwareDetected();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -289,512 +229,73 @@ public class FaceService extends BiometricServiceBase<IBiometricsFace> {
@Override // Binder call
public List<Face> getEnrolledFaces(int userId, String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
- return FaceService.this.getEnrolledTemplates(userId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ return mFace10.getEnrolledFaces(userId);
}
@Override // Binder call
public boolean hasEnrolledFaces(int userId, String opPackageName) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- return FaceService.this.hasEnrolledBiometrics(userId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ return !mFace10.getEnrolledFaces(userId).isEmpty();
+ }
+
+ @Override // Binder call
+ public FaceSensorProperties getSensorProperties(String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ return mFace10.getFaceSensorProperties();
}
@Override
public @LockoutTracker.LockoutMode int getLockoutModeForUser(int userId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- return mLockoutTracker.getLockoutModeForUser(userId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ return mFace10.getLockoutModeForUser(userId);
}
@Override // Binder call
- public long getAuthenticatorId(int callingUserId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- return FaceService.this.getAuthenticatorId(callingUserId);
+ public long getAuthenticatorId(int userId) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ return mFace10.getAuthenticatorId(userId);
}
@Override // Binder call
public void resetLockout(int userId, byte[] hardwareAuthToken) {
- checkPermission(MANAGE_BIOMETRIC);
- mHandler.post(() -> {
- if (!FaceService.this.hasEnrolledBiometrics(userId)) {
- Slog.w(TAG, "Ignoring lockout reset, no templates enrolled");
- return;
- }
-
- Slog.d(TAG, "Resetting lockout for user: " + userId);
-
- updateActiveGroup(userId);
- final FaceResetLockoutClient client = new FaceResetLockoutClient(getContext(),
- mLazyDaemon, userId, getContext().getOpPackageName(), getSensorId(),
- hardwareAuthToken);
- startClient(client, true /* initiatedByClient */);
- });
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.scheduleResetLockout(userId, hardwareAuthToken);
}
@Override
public void setFeature(final IBinder token, int userId, int feature, boolean enabled,
final byte[] hardwareAuthToken, IFaceServiceReceiver receiver,
final String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
-
- mHandler.post(() -> {
- if (DEBUG) {
- Slog.d(TAG, "setFeature for user(" + userId + ")");
- }
- updateActiveGroup(userId);
- if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
- Slog.e(TAG, "No enrolled biometrics while setting feature: " + feature);
- return;
- }
-
- final int faceId = getFirstTemplateForUser(mCurrentUserId);
-
- final FaceSetFeatureClient client = new FaceSetFeatureClient(getContext(),
- mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
- opPackageName, getSensorId(), feature, enabled, hardwareAuthToken, faceId);
- startClient(client, true /* initiatedByClient */);
- });
-
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10.scheduleSetFeature(token, userId, feature, enabled, hardwareAuthToken, receiver,
+ opPackageName);
}
@Override
public void getFeature(final IBinder token, int userId, int feature,
IFaceServiceReceiver receiver, final String opPackageName) {
- checkPermission(MANAGE_BIOMETRIC);
-
- mHandler.post(() -> {
- if (DEBUG) {
- Slog.d(TAG, "getFeature for user(" + userId + ")");
- }
- updateActiveGroup(userId);
- // This should ideally return tri-state, but the user isn't shown settings unless
- // they are enrolled so it's fine for now.
- if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
- Slog.e(TAG, "No enrolled biometrics while getting feature: " + feature);
- return;
- }
-
- // TODO: Support multiple faces
- final int faceId = getFirstTemplateForUser(mCurrentUserId);
-
- final FaceGetFeatureClient client = new FaceGetFeatureClient(getContext(),
- mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
- opPackageName, getSensorId(), feature, faceId);
- startClient(client, true /* initiatedByClient */);
- });
-
- }
-
- // TODO: Support multiple faces
- private int getFirstTemplateForUser(int user) {
- final List<Face> faces = FaceService.this.getEnrolledTemplates(user);
- if (!faces.isEmpty()) {
- return faces.get(0).getBiometricId();
- }
- return 0;
+ Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
+ mFace10.scheduleGetFeature(token, userId, feature, receiver, opPackageName);
}
@Override // Binder call
public void initializeConfiguration(int sensorId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- initializeConfigurationInternal(sensorId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ mFace10 = new Face10(getContext(), sensorId, mLockoutResetDispatcher);
}
}
- private final LockoutHalImpl mLockoutTracker;
-
- @GuardedBy("this")
- private IBiometricsFace mDaemon;
- private UsageStats mUsageStats;
- private FaceRevokeChallengeClient mPendingRevokeChallenge;
-
- private NotificationManager mNotificationManager;
-
- /**
- * Receives callbacks from the HAL.
- */
- private IBiometricsFaceClientCallback mDaemonCallback =
- new IBiometricsFaceClientCallback.Stub() {
- @Override
- public void onEnrollResult(final long deviceId, int faceId, int userId,
- int remaining) {
- mHandler.post(() -> {
- final Face face = new Face(getBiometricUtils()
- .getUniqueName(getContext(), userId), faceId, deviceId);
- FaceService.super.handleEnrollResult(face, remaining);
-
- // Enrollment changes the authenticatorId, so update it here.
- IBiometricsFace daemon = getFaceDaemon();
- if (remaining == 0 && daemon != null) {
- try {
- mAuthenticatorIds.put(userId,
- hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value
- : 0L);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get authenticatorId", e);
- }
- }
- });
- }
-
- @Override
- public void onAcquired(final long deviceId, final int userId, final int acquiredInfo,
- final int vendorCode) {
- mHandler.post(() -> {
- FaceService.super.handleAcquired(acquiredInfo, vendorCode);
- });
- }
-
- @Override
- public void onAuthenticated(final long deviceId, final int faceId, final int userId,
- ArrayList<Byte> token) {
- mHandler.post(() -> {
- Face face = new Face("", faceId, deviceId);
- FaceService.super.handleAuthenticated(face, token);
- });
- }
-
- @Override
- public void onError(final long deviceId, final int userId, final int error,
- final int vendorCode) {
- mHandler.post(() -> {
- FaceService.super.handleError(error, vendorCode);
-
- // TODO: this chunk of code should be common to all biometric services
- if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) {
- // If we get HW_UNAVAILABLE, try to connect again later...
- Slog.w(TAG, "Got ERROR_HW_UNAVAILABLE; try reconnecting next client.");
- synchronized (this) {
- mDaemon = null;
- mCurrentUserId = UserHandle.USER_NULL;
- }
- }
- });
- }
-
- @Override
- public void onRemoved(final long deviceId, ArrayList<Integer> faceIds, final int userId) {
- mHandler.post(() -> {
- if (!faceIds.isEmpty()) {
- for (int i = 0; i < faceIds.size(); i++) {
- final Face face = new Face("", faceIds.get(i), deviceId);
- // Convert to old behavior
- FaceService.super.handleRemoved(face, faceIds.size() - i - 1);
- }
- } else {
- final Face face = new Face("", 0 /* identifier */, deviceId);
- FaceService.super.handleRemoved(face, 0 /* remaining */);
- }
- Settings.Secure.putIntForUser(getContext().getContentResolver(),
- Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
- });
- }
-
- @Override
- public void onEnumerate(long deviceId, ArrayList<Integer> faceIds, int userId)
- throws RemoteException {
- mHandler.post(() -> {
- if (!faceIds.isEmpty()) {
- for (int i = 0; i < faceIds.size(); i++) {
- final Face face = new Face("", faceIds.get(i), deviceId);
- // Convert to old old behavior
- FaceService.super.handleEnumerate(face, faceIds.size() - i - 1);
- }
- } else {
- // For face, the HIDL contract is to receive an empty list when there are no
- // templates enrolled. Send a null identifier since we don't consume them
- // anywhere, and send remaining == 0 to plumb this with existing common code.
- FaceService.super.handleEnumerate(null /* identifier */, 0);
- }
- });
- }
-
- @Override
- public void onLockoutChanged(long duration) {
- Slog.d(TAG, "onLockoutChanged: " + duration);
-
- final @LockoutTracker.LockoutMode int lockoutMode;
- if (duration == 0) {
- lockoutMode = LockoutTracker.LOCKOUT_NONE;
- } else if (duration == -1 || duration == Long.MAX_VALUE) {
- lockoutMode = LockoutTracker.LOCKOUT_PERMANENT;
- } else {
- lockoutMode = LockoutTracker.LOCKOUT_TIMED;
- }
- mLockoutTracker.setCurrentUserLockoutMode(lockoutMode);
-
- mHandler.post(() -> {
- if (duration == 0) {
- mLockoutResetTracker.notifyLockoutResetCallbacks(getSensorId());
- }
- });
- }
- };
-
public FaceService(Context context) {
super(context);
- mLazyDaemon = FaceService.this::getFaceDaemon;
- mLockoutResetTracker = new LockoutResetTracker(context);
- mLockoutTracker = new LockoutHalImpl();
- mUsageStats = new UsageStats(context);
- mNotificationManager = getContext().getSystemService(NotificationManager.class);
- }
-
- @Override
- protected void removeClient(ClientMonitor<?> client) {
- super.removeClient(client);
- if (mPendingRevokeChallenge != null) {
- revokeChallengeInternal(mPendingRevokeChallenge);
- mPendingRevokeChallenge = null;
- }
+ mLockoutResetDispatcher = new LockoutResetDispatcher(context);
+ mLockPatternUtils = new LockPatternUtils(context);
}
@Override
public void onStart() {
- super.onStart();
publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
- // Get the face daemon on FaceService's on thread so SystemServerInitThreadPool isn't
- // blocked
- SystemServerInitThreadPool.submit(() -> mHandler.post(this::getFaceDaemon),
- TAG + ".onStart");
- }
-
- @Override
- public String getTag() {
- return TAG;
- }
-
- @Override
- protected IBiometricsFace getDaemon() {
- return getFaceDaemon();
- }
-
- @Override
- protected BiometricUtils getBiometricUtils() {
- return FaceUtils.getInstance();
- }
-
- @Override
- protected boolean hasReachedEnrollmentLimit(int userId) {
- final int limit = getContext().getResources().getInteger(
- com.android.internal.R.integer.config_faceMaxTemplatesPerUser);
- final int enrolled = FaceService.this.getEnrolledTemplates(userId).size();
- if (enrolled >= limit) {
- Slog.w(TAG, "Too many faces registered, user: " + userId);
- return true;
- }
- return false;
- }
-
- @Override
- public void serviceDied(long cookie) {
- super.serviceDied(cookie);
- mDaemon = null;
-
- mCurrentUserId = UserHandle.USER_NULL; // Force updateActiveGroup() to re-evaluate
- }
-
- @Override
- protected void updateActiveGroup(int userId) {
- IBiometricsFace daemon = getFaceDaemon();
-
- if (daemon != null) {
- try {
- if (userId != mCurrentUserId) {
- final File baseDir = Environment.getDataVendorDeDirectory(userId);
- final File faceDir = new File(baseDir, FACE_DATA_DIR);
- if (!faceDir.exists()) {
- if (!faceDir.mkdir()) {
- Slog.v(TAG, "Cannot make directory: " + faceDir.getAbsolutePath());
- return;
- }
- // Calling mkdir() from this process will create a directory with our
- // permissions (inherited from the containing dir). This command fixes
- // the label.
- if (!SELinux.restorecon(faceDir)) {
- Slog.w(TAG, "Restorecons failed. Directory will have wrong label.");
- return;
- }
- }
-
- daemon.setActiveUser(userId, faceDir.getAbsolutePath());
- mCurrentUserId = userId;
- mAuthenticatorIds.put(userId,
- hasEnrolledBiometrics(userId) ? daemon.getAuthenticatorId().value : 0L);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to setActiveUser():", e);
- }
- }
- }
-
- @Override
- protected void handleUserSwitching(int userId) {
- super.handleUserSwitching(userId);
- // Will be updated when we get the callback from HAL
- mLockoutTracker.setCurrentUserLockoutMode(LockoutTracker.LOCKOUT_NONE);
- }
-
- @Override
- protected boolean hasEnrolledBiometrics(int userId) {
- if (userId != UserHandle.getCallingUserId()) {
- checkPermission(INTERACT_ACROSS_USERS);
- }
- return getBiometricUtils().getBiometricsForUser(getContext(), userId).size() > 0;
- }
-
- @Override
- protected String getManageBiometricPermission() {
- return MANAGE_BIOMETRIC;
- }
-
- @Override
- protected List<Face> getEnrolledTemplates(int userId) {
- return FaceUtils.getInstance().getBiometricsForUser(getContext(), userId);
- }
-
- @Override
- protected void notifyClientActiveCallbacks(boolean isActive) {
- // noop for Face.
- }
-
- @Override
- protected int statsModality() {
- return BiometricsProtoEnums.MODALITY_FACE;
- }
-
- @Override
- protected void doTemplateCleanupForUser(int userId) {
- final List<Face> enrolledList = getEnrolledTemplates(userId);
- final FaceInternalCleanupClient client = new FaceInternalCleanupClient(getContext(),
- mLazyDaemon, userId, getContext().getOpPackageName(), getSensorId(), enrolledList,
- getBiometricUtils(), mAuthenticatorIds);
- cleanupInternal(client);
- }
-
-
- /** Gets the face daemon */
- private synchronized IBiometricsFace getFaceDaemon() {
- if (mDaemon == null) {
- Slog.v(TAG, "mDaemon was null, reconnect to face");
- try {
- mDaemon = IBiometricsFace.getService();
- } catch (java.util.NoSuchElementException e) {
- // Service doesn't exist or cannot be opened. Logged below.
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to get biometric interface", e);
- }
- if (mDaemon == null) {
- Slog.w(TAG, "face HIDL not available");
- return null;
- }
-
- mDaemon.asBinder().linkToDeath(this, 0);
-
- long halId = 0;
- try {
- halId = mDaemon.setCallback(mDaemonCallback).value;
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to open face HAL", e);
- mDaemon = null; // try again later!
- }
-
- if (DEBUG) Slog.v(TAG, "Face HAL id: " + halId);
- if (halId != 0) {
- loadAuthenticatorIds();
- updateActiveGroup(ActivityManager.getCurrentUser());
- doTemplateCleanupForUser(ActivityManager.getCurrentUser());
- } else {
- Slog.w(TAG, "Failed to open Face HAL!");
- MetricsLogger.count(getContext(), "faced_openhal_error", 1);
- mDaemon = null;
- }
- }
- return mDaemon;
}
private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
-
- private void dumpInternal(PrintWriter pw) {
- PerformanceTracker performanceTracker =
- PerformanceTracker.getInstanceForSensorId(getSensorId());
-
- JSONObject dump = new JSONObject();
- try {
- dump.put("service", "Face Manager");
-
- JSONArray sets = new JSONArray();
- for (UserInfo user : UserManager.get(getContext()).getUsers()) {
- final int userId = user.getUserHandle().getIdentifier();
- final int N = getBiometricUtils().getBiometricsForUser(getContext(), userId).size();
- JSONObject set = new JSONObject();
- set.put("id", userId);
- set.put("count", N);
- set.put("accept", performanceTracker.getAcceptForUser(userId));
- set.put("reject", performanceTracker.getRejectForUser(userId));
- set.put("acquire", performanceTracker.getAcquireForUser(userId));
- set.put("lockout", performanceTracker.getTimedLockoutForUser(userId));
- set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId));
- // cryptoStats measures statistics about secure face transactions
- // (e.g. to unlock password storage, make secure purchases, etc.)
- set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId));
- set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId));
- set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId));
- sets.put(set);
- }
-
- dump.put("prints", sets);
- } catch (JSONException e) {
- Slog.e(TAG, "dump formatting failure", e);
- }
- pw.println(dump);
- pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount());
-
- mUsageStats.print(pw);
- }
-
- private void dumpHal(FileDescriptor fd, String[] args) {
- // WARNING: CDD restricts image data from leaving TEE unencrypted on
- // production devices:
- // [C-1-10] MUST not allow unencrypted access to identifiable biometric
- // data or any data derived from it (such as embeddings) to the
- // Application Processor outside the context of the TEE.
- // As such, this API should only be enabled for testing purposes on
- // engineering and userdebug builds. All modules in the software stack
- // MUST enforce final build products do NOT have this functionality.
- // Additionally, the following check MUST NOT be removed.
- if (!(Build.IS_ENG || Build.IS_USERDEBUG)) {
- return;
- }
-
- // Additionally, this flag allows turning off face for a device
- // (either permanently through the build or on an individual device).
- if (SystemProperties.getBoolean("ro.face.disable_debug_data", false)
- || SystemProperties.getBoolean("persist.face.disable_debug_data", false)) {
- return;
- }
-
- // The debug method takes two file descriptors. The first is for text
- // output, which we will drop. The second is for binary data, which
- // will be the protobuf data.
- final IBiometricsFace daemon = getFaceDaemon();
- if (daemon != null) {
- FileOutputStream devnull = null;
- try {
- devnull = new FileOutputStream("/dev/null");
- final NativeHandle handle = new NativeHandle(
- new FileDescriptor[] { devnull.getFD(), fd },
- new int[0], false);
- daemon.debug(handle, new ArrayList<String>(Arrays.asList(args)));
- } catch (IOException | RemoteException ex) {
- Slog.d(TAG, "error while reading face debugging data", ex);
- } finally {
- if (devnull != null) {
- try {
- devnull.close();
- } catch (IOException ex) {
- }
- }
- }
- }
- }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java
new file mode 100644
index 000000000000..bcf304e47816
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceUpdateActiveUserClient.java
@@ -0,0 +1,94 @@
+/*
+ * 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.biometrics.sensors.face;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.face.V1_0.IBiometricsFace;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.ClientMonitor;
+
+import java.io.File;
+import java.util.Map;
+
+public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
+ private static final String TAG = "FaceUpdateActiveUserClient";
+ private static final String FACE_DATA_DIR = "facedata";
+
+ private final int mCurrentUserId;
+ private final boolean mHasEnrolledBiometrics;
+ @NonNull private final Map<Integer, Long> mAuthenticatorIds;
+
+ FaceUpdateActiveUserClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, int userId, @NonNull String owner,
+ int sensorId, int currentUserId, boolean hasEnrolledBIometrics,
+ @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);
+ mCurrentUserId = currentUserId;
+ mHasEnrolledBiometrics = hasEnrolledBIometrics;
+ mAuthenticatorIds = authenticatorIds;
+ }
+
+ @Override
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
+
+ if (mCurrentUserId == getTargetUserId()) {
+ Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId");
+ try {
+ mAuthenticatorIds.put(getTargetUserId(), mHasEnrolledBiometrics
+ ? getFreshDaemon().getAuthenticatorId().value : 0L);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to refresh authenticatorId", e);
+ }
+ finishCallback.onClientFinished(this, true /* success */);
+ return;
+ }
+
+ startHalOperation();
+ }
+
+ @Override
+ public void unableToStart() {
+ // Nothing to do here
+ }
+
+ @Override
+ protected void startHalOperation() {
+ final File storePath = new File(Environment.getDataVendorDeDirectory(getTargetUserId()),
+ FACE_DATA_DIR);
+ if (!storePath.exists()) {
+ Slog.e(TAG, "vold has not created the directory?");
+ mFinishCallback.onClientFinished(this, false /* success */);
+ return;
+ }
+
+ try {
+ getFreshDaemon().setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
+ mFinishCallback.onClientFinished(this, true /* success */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to setActiveUser: " + e);
+ mFinishCallback.onClientFinished(this, false /* success */);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
index 0a9497291f37..20ee3f375ab1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/Fingerprint21.java
@@ -51,12 +51,13 @@ import com.android.server.biometrics.fingerprint.FingerprintUserStatsProto;
import com.android.server.biometrics.fingerprint.PerformanceStatsProto;
import com.android.server.biometrics.sensors.AcquisitionClient;
import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.AuthenticationConsumer;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.Interruptable;
-import com.android.server.biometrics.sensors.LockoutResetTracker;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.PerformanceTracker;
import com.android.server.biometrics.sensors.RemovalConsumer;
@@ -83,17 +84,17 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
private static final int ENROLL_TIMEOUT_SEC = 60;
private final Context mContext;
- private final IActivityTaskManager mActivityTaskManager;;
+ private final IActivityTaskManager mActivityTaskManager;
private final SensorProperties mSensorProperties;
private final BiometricScheduler mScheduler;
private final Handler mHandler;
- private final LockoutResetTracker mLockoutResetTracker;
+ private final LockoutResetDispatcher mLockoutResetDispatcher;
private final LockoutFrameworkImpl mLockoutTracker;
private final BiometricTaskStackListener mTaskStackListener;
private final ClientMonitor.LazyDaemon<IBiometricsFingerprint> mLazyDaemon;
private final Map<Integer, Long> mAuthenticatorIds;
- private IBiometricsFingerprint mDaemon;
+ @Nullable private IBiometricsFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
private int mCurrentUserId = UserHandle.USER_NULL;
@@ -101,12 +102,18 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
* Static properties that never change for a given sensor.
*/
private static final class SensorProperties {
+ // Unique sensorId
final int sensorId;
- final Boolean isUdfps;
+ // Is the sensor under-display
+ final boolean isUdfps;
+ // Supports finger detection without exposing accept/reject and without incrementing the
+ // lockout counter
+ final boolean supportsFingerDetectOnly;
- SensorProperties(int sensorId, Boolean isUdfps) {
+ SensorProperties(int sensorId, boolean isUdfps, boolean supportsFingerDetectOnly) {
this.sensorId = sensorId;
this.isUdfps = isUdfps;
+ this.supportsFingerDetectOnly = supportsFingerDetectOnly;
}
}
@@ -146,7 +153,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
new LockoutFrameworkImpl.LockoutResetCallback() {
@Override
public void onLockoutReset(int userId) {
- mLockoutResetTracker.notifyLockoutResetCallbacks(mSensorProperties.sensorId);
+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorProperties.sensorId);
}
};
@@ -157,9 +164,8 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
}
};
- private IBiometricsFingerprintClientCallback mDaemonCallback =
+ private final IBiometricsFingerprintClientCallback mDaemonCallback =
new IBiometricsFingerprintClientCallback.Stub() {
-
@Override
public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
mHandler.post(() -> {
@@ -169,19 +175,13 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof FingerprintEnrollClient)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onEnrollResult for non-enroll client: " + clientName);
+ Slog.e(TAG, "onEnrollResult for non-enroll client: "
+ + Utils.getClientName(client));
return;
}
final FingerprintEnrollClient enrollClient = (FingerprintEnrollClient) client;
enrollClient.onEnrollResult(fingerprint, remaining);
-
- if (remaining == 0) {
- // Update the framework's authenticatorId cache for this user
- scheduleUpdateActiveUserWithoutHandler(mCurrentUserId);
- }
});
}
@@ -195,9 +195,8 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
mHandler.post(() -> {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof AcquisitionClient)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onAcquired for non-acquisition client: " + clientName);
+ Slog.e(TAG, "onAcquired for non-acquisition client: "
+ + Utils.getClientName(client));
return;
}
@@ -211,18 +210,17 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
ArrayList<Byte> token) {
mHandler.post(() -> {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
- if (!(client instanceof FingerprintAuthenticationClient)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onAuthenticated for non-authentication client: " + clientName);
+ if (!(client instanceof AuthenticationConsumer)) {
+ Slog.e(TAG, "onAuthenticated for non-authentication consumer: "
+ + Utils.getClientName(client));
return;
}
- final FingerprintAuthenticationClient authenticationClient =
- (FingerprintAuthenticationClient) client;
+ final AuthenticationConsumer authenticationConsumer =
+ (AuthenticationConsumer) client;
final boolean authenticated = fingerId != 0;
final Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
- authenticationClient.onAuthenticated(fp, authenticated, token);
+ authenticationConsumer.onAuthenticated(fp, authenticated, token);
});
}
@@ -235,9 +233,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
+ ", error: " + error
+ ", vendorCode: " + vendorCode);
if (!(client instanceof Interruptable)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onError for non-error consumer: " + clientName);
+ Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName(client));
return;
}
@@ -258,9 +254,8 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
Slog.d(TAG, "Removed, fingerId: " + fingerId + ", remaining: " + remaining);
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof RemovalConsumer)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onRemoved for non-removal consumer: " + clientName);
+ Slog.e(TAG, "onRemoved for non-removal consumer: "
+ + Utils.getClientName(client));
return;
}
@@ -275,9 +270,8 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
mHandler.post(() -> {
final ClientMonitor<?> client = mScheduler.getCurrentClient();
if (!(client instanceof EnumerateConsumer)) {
- final String clientName = client != null
- ? client.getClass().getSimpleName(): "null";
- Slog.e(TAG, "onEnumerate for non-enumerate consumer: " + clientName);
+ Slog.e(TAG, "onEnumerate for non-enumerate consumer: "
+ + Utils.getClientName(client));
return;
}
@@ -289,17 +283,17 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
};
Fingerprint21(@NonNull Context context, int sensorId,
- @NonNull LockoutResetTracker lockoutResetTracker,
- @NonNull GestureAvailabilityTracker gestureAvailabilityTracker) {
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
mContext = context;
mActivityTaskManager = ActivityTaskManager.getService();
mHandler = new Handler(Looper.getMainLooper());
mTaskStackListener = new BiometricTaskStackListener();
mAuthenticatorIds = Collections.synchronizedMap(new HashMap<>());
mLazyDaemon = Fingerprint21.this::getDaemon;
- mLockoutResetTracker = lockoutResetTracker;
+ mLockoutResetDispatcher = lockoutResetDispatcher;
mLockoutTracker = new LockoutFrameworkImpl(context, mLockoutResetCallback);
- mScheduler = new BiometricScheduler(TAG, gestureAvailabilityTracker);
+ mScheduler = new BiometricScheduler(TAG, gestureAvailabilityDispatcher);
try {
ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
@@ -308,7 +302,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
}
final IBiometricsFingerprint daemon = getDaemon();
- Boolean isUdfps = false;
+ boolean isUdfps = false;
android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint extension =
android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint.castFrom(
daemon);
@@ -317,10 +311,12 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
isUdfps = extension.isUdfps(sensorId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception while quering udfps", e);
- isUdfps = null;
+ isUdfps = false;
}
}
- mSensorProperties = new SensorProperties(sensorId, isUdfps);
+ // Fingerprint2.1 supports finger-detect only since lockout is controlled in the framework.
+ mSensorProperties = new SensorProperties(sensorId, isUdfps,
+ true /* supportsFingerDetectOnly */);
}
@Override
@@ -414,9 +410,15 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
}
}
});
-
}
+ /**
+ * Schedules the {@link FingerprintUpdateActiveUserClient} without posting the work onto the
+ * handler. Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser"
+ * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule
+ * this operation on the same lambda/runnable as those operations so that the ordering is
+ * correct.
+ */
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
final boolean hasEnrolled = !getEnrolledFingerprints(targetUserId).isEmpty();
final FingerprintUpdateActiveUserClient client =
@@ -467,9 +469,13 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName, FingerprintUtils.getInstance(),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController);
- mScheduler.scheduleClientMonitor(client);
+ mScheduler.scheduleClientMonitor(client, ((clientMonitor, success) -> {
+ if (success) {
+ // Update authenticatorIds
+ scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId());
+ }
+ }));
});
-
}
void cancelEnrollment(@NonNull IBinder token) {
@@ -478,6 +484,21 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
});
}
+ void scheduleFingerDetect(@NonNull IBinder token, int userId,
+ @NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
+ @Nullable Surface surface, int statsClient) {
+ mHandler.post(() -> {
+ scheduleUpdateActiveUserWithoutHandler(userId);
+
+ final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
+ final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
+ mLazyDaemon, token, listener, userId, opPackageName,
+ mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
+ statsClient);
+ mScheduler.scheduleClientMonitor(client);
+ });
+ }
+
void scheduleAuthenticate(@NonNull IBinder token, long operationId, int userId, int cookie,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
@Nullable Surface surface, boolean restricted, int statsClient) {
@@ -533,7 +554,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
}
boolean isHardwareDetected() {
- IBiometricsFingerprint daemon = getDaemon();
+ final IBiometricsFingerprint daemon = getDaemon();
return daemon != null;
}
@@ -619,7 +640,7 @@ class Fingerprint21 implements IHwBinder.DeathRecipient {
tracker.clear();
}
- void dumpInternal(PrintWriter pw) {
+ void dumpInternal(@NonNull PrintWriter pw) {
PerformanceTracker performanceTracker =
PerformanceTracker.getInstanceForSensorId(mSensorProperties.sensorId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
index 1999a0f0c9d2..1564056cfdbd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticationClient.java
@@ -66,26 +66,6 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
mUdfpsOverlayController = udfpsOverlayController;
}
- private void showUdfpsOverlay() {
- if (mUdfpsOverlayController != null) {
- try {
- mUdfpsOverlayController.showUdfpsOverlay();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
- }
- }
- }
-
- private void hideUdfpsOverlay() {
- if (mUdfpsOverlayController != null) {
- try {
- mUdfpsOverlayController.hideUdfpsOverlay();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
- }
- }
- }
-
@Override
public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
boolean authenticated, ArrayList<Byte> token) {
@@ -98,7 +78,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
if (authenticated) {
resetFailedAttempts(getTargetUserId());
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, true /* success */);
} else {
final @LockoutTracker.LockoutMode int lockoutMode =
@@ -111,7 +91,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
// Send the error, but do not invoke the FinishCallback yet. Since lockout is not
// controlled by the HAL, the framework must stop the sensor before finishing the
// client.
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
onErrorInternal(errorCode, 0 /* vendorCode */, false /* finish */);
cancel();
}
@@ -130,7 +110,7 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
@Override
protected void startHalOperation() {
- showUdfpsOverlay();
+ UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
getFreshDaemon().authenticate(mOperationId, getTargetUserId());
@@ -138,14 +118,14 @@ class FingerprintAuthenticationClient extends AuthenticationClient<IBiometricsFi
Slog.e(TAG, "Remote exception when requesting auth", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
try {
getFreshDaemon().cancel();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java
new file mode 100644
index 000000000000..8b295f8f4931
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintDetectClient.java
@@ -0,0 +1,123 @@
+/*
+ * 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.biometrics.sensors.fingerprint;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.biometrics.BiometricAuthenticator;
+import android.hardware.biometrics.BiometricFingerprintConstants;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.IUdfpsOverlayController;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.server.biometrics.sensors.AcquisitionClient;
+import com.android.server.biometrics.sensors.AuthenticationConsumer;
+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
+import com.android.server.biometrics.sensors.PerformanceTracker;
+
+import java.util.ArrayList;
+
+/**
+ * Performs fingerprint detection without exposing any matching information (e.g. accept/reject
+ * have the same haptic, lockout counter is not increased).
+ */
+class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
+ implements AuthenticationConsumer, Udfps {
+
+ private static final String TAG = "FingerprintDetectClient";
+
+ private final boolean mIsStrongBiometric;
+ @Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+
+ public FingerprintDetectClient(@NonNull Context context,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+ @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
+ int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController,
+ boolean isStrongBiometric, int statsClient) {
+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
+ BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
+ statsClient);
+ mUdfpsOverlayController = udfpsOverlayController;
+ mIsStrongBiometric = isStrongBiometric;
+ }
+
+ @Override
+ protected void stopHalOperation() {
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ try {
+ getFreshDaemon().cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting cancel", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ mFinishCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public void start(@NonNull FinishCallback finishCallback) {
+ super.start(finishCallback);
+ startHalOperation();
+ }
+
+ @Override
+ protected void startHalOperation() {
+ UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
+ try {
+ getFreshDaemon().authenticate(0 /* operationId */, getTargetUserId());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when requesting auth", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
+ mFinishCallback.onClientFinished(this, false /* success */);
+ }
+ }
+
+ @Override
+ public void onFingerDown(int x, int y, float minor, float major) {
+ UdfpsHelper.onFingerDown(getFreshDaemon(), x, y, minor, major);
+ }
+
+ @Override
+ public void onFingerUp() {
+ UdfpsHelper.onFingerUp(getFreshDaemon());
+ }
+
+ @Override
+ public void onAuthenticated(BiometricAuthenticator.Identifier identifier, boolean authenticated,
+ ArrayList<Byte> hardwareAuthToken) {
+ logOnAuthenticated(getContext(), authenticated, false /* requireConfirmation */,
+ getTargetUserId(), false /* isBiometricPrompt */);
+
+ // Do not distinguish between success/failures.
+ vibrateSuccess();
+
+ final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
+ pm.incrementAuthForUser(getTargetUserId(), authenticated);
+
+ try {
+ getListener().onDetected(getSensorId(), getTargetUserId(), mIsStrongBiometric);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when sending onDetected", e);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
index c26dbfdaa75b..32f8b8fe8b26 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintEnrollClient.java
@@ -55,29 +55,22 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
mUdfpsOverlayController = udfpsOverlayController;
}
- private void showUdfpsOverlay() {
- if (mUdfpsOverlayController != null) {
- try {
- mUdfpsOverlayController.showUdfpsOverlay();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
- }
- }
- }
-
- private void hideUdfpsOverlay() {
- if (mUdfpsOverlayController != null) {
- try {
- mUdfpsOverlayController.hideUdfpsOverlay();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
- }
+ @Override
+ protected boolean hasReachedEnrollmentLimit() {
+ final int limit = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_fingerprintMaxTemplatesPerUser);
+ final int enrolled = mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId())
+ .size();
+ if (enrolled >= limit) {
+ Slog.w(TAG, "Too many faces registered, user: " + getTargetUserId());
+ return true;
}
+ return false;
}
@Override
protected void startHalOperation() {
- showUdfpsOverlay();
+ UdfpsHelper.showUdfpsOverlay(mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
getFreshDaemon().enroll(mHardwareAuthToken, getTargetUserId(), mTimeoutSec);
@@ -85,14 +78,14 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
Slog.e(TAG, "Remote exception when requesting enroll", e);
onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
0 /* vendorCode */);
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
mFinishCallback.onClientFinished(this, false /* success */);
}
}
@Override
protected void stopHalOperation() {
- hideUdfpsOverlay();
+ UdfpsHelper.hideUdfpsOverlay(mUdfpsOverlayController);
try {
getFreshDaemon().cancel();
} catch (RemoteException e) {
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 d092bfd02b7b..4d33fd6301e2 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
@@ -25,6 +25,7 @@ import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.Context;
@@ -43,14 +44,16 @@ import android.os.NativeHandle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.EventLog;
import android.util.Slog;
import android.view.Surface;
import com.android.internal.util.DumpUtils;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
-import com.android.server.biometrics.sensors.LockoutResetTracker;
+import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import java.io.FileDescriptor;
@@ -68,8 +71,9 @@ public class FingerprintService extends SystemService {
protected static final String TAG = "FingerprintService";
private final AppOpsManager mAppOps;
- private final LockoutResetTracker mLockoutResetTracker;
- private final GestureAvailabilityTracker mGestureAvailabilityTracker;
+ private final LockoutResetDispatcher mLockoutResetDispatcher;
+ private final GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
+ private final LockPatternUtils mLockPatternUtils;
private Fingerprint21 mFingerprint21;
/**
@@ -107,7 +111,7 @@ public class FingerprintService extends SystemService {
@Override // Binder call
public void authenticate(final IBinder token, final long operationId, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName,
- Surface surface) {
+ final Surface surface) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
@@ -118,6 +122,15 @@ public class FingerprintService extends SystemService {
return;
}
+ if (Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)
+ && Utils.isKeyguard(getContext(), opPackageName)) {
+ // If this happens, something in KeyguardUpdateMonitor is wrong.
+ // SafetyNet for b/79776455
+ EventLog.writeEvent(0x534e4554, "79776455");
+ Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown");
+ return;
+ }
+
final boolean restricted = getContext().checkCallingPermission(MANAGE_FINGERPRINT)
!= PackageManager.PERMISSION_GRANTED;
final int statsClient = Utils.isKeyguard(getContext(), opPackageName)
@@ -128,6 +141,28 @@ public class FingerprintService extends SystemService {
restricted, statsClient);
}
+ @Override
+ public void detectFingerprint(final IBinder token, final int userId,
+ final IFingerprintServiceReceiver receiver, final String opPackageName,
+ final Surface surface) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (!Utils.isKeyguard(getContext(), opPackageName)) {
+ Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
+ return;
+ }
+
+ if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
+ // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
+ // ever be invoked when the user is encrypted or lockdown.
+ Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
+ return;
+ }
+
+ mFingerprint21.scheduleFingerDetect(token, userId,
+ new ClientMonitorCallbackConverter(receiver), opPackageName, surface,
+ BiometricsProtoEnums.CLIENT_KEYGUARD);
+ }
+
@Override // Binder call
public void prepareForAuthentication(IBinder token, long operationId, int userId,
IBiometricSensorReceiver sensorReceiver, String opPackageName,
@@ -164,6 +199,20 @@ public class FingerprintService extends SystemService {
}
@Override // Binder call
+ public void cancelFingerprintDetect(final IBinder token, final String opPackageName) {
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
+ if (!Utils.isKeyguard(getContext(), opPackageName)) {
+ Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: "
+ + opPackageName);
+ return;
+ }
+
+ // For IBiometricsFingerprint2.1, cancelling fingerprint detect is the same as
+ // cancelling authentication.
+ mFingerprint21.cancelAuthentication(token);
+ }
+
+ @Override // Binder call
public void cancelAuthenticationFromService(final IBinder token, final String opPackageName,
int callingUid, int callingPid, int callingUserId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
@@ -181,11 +230,11 @@ public class FingerprintService extends SystemService {
public void addLockoutResetCallback(final IBiometricServiceLockoutResetCallback callback,
final String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mLockoutResetTracker.addCallback(callback, opPackageName);
+ mLockoutResetDispatcher.addCallback(callback, opPackageName);
}
@Override // Binder call
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
}
@@ -212,6 +261,10 @@ public class FingerprintService extends SystemService {
final long token = Binder.clearCallingIdentity();
try {
+ if (mFingerprint21 == null) {
+ Slog.e(TAG, "No HAL, caller: " + opPackageName);
+ return false;
+ }
return mFingerprint21.isHardwareDetected();
} finally {
Binder.restoreCallingIdentity(token);
@@ -277,26 +330,26 @@ public class FingerprintService extends SystemService {
@Override
public boolean isClientActive() {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- return mGestureAvailabilityTracker.isAnySensorActive();
+ return mGestureAvailabilityDispatcher.isAnySensorActive();
}
@Override
public void addClientActiveCallback(IFingerprintClientActiveCallback callback) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mGestureAvailabilityTracker.registerCallback(callback);
+ mGestureAvailabilityDispatcher.registerCallback(callback);
}
@Override
public void removeClientActiveCallback(IFingerprintClientActiveCallback callback) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
- mGestureAvailabilityTracker.removeCallback(callback);
+ mGestureAvailabilityDispatcher.removeCallback(callback);
}
@Override // Binder call
public void initializeConfiguration(int sensorId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
- mFingerprint21 = new Fingerprint21(getContext(), sensorId, mLockoutResetTracker,
- mGestureAvailabilityTracker);
+ mFingerprint21 = new Fingerprint21(getContext(), sensorId, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher);
}
@Override
@@ -312,7 +365,7 @@ public class FingerprintService extends SystemService {
}
@Override
- public boolean isUdfps(int sensorId) {
+ public boolean isUdfps() {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
return mFingerprint21.isUdfps();
}
@@ -327,8 +380,9 @@ public class FingerprintService extends SystemService {
public FingerprintService(Context context) {
super(context);
mAppOps = context.getSystemService(AppOpsManager.class);
- mGestureAvailabilityTracker = new GestureAvailabilityTracker();
- mLockoutResetTracker = new LockoutResetTracker(context);
+ mGestureAvailabilityDispatcher = new GestureAvailabilityDispatcher();
+ mLockoutResetDispatcher = new LockoutResetDispatcher(context);
+ mLockPatternUtils = new LockPatternUtils(context);
}
@Override
@@ -336,6 +390,9 @@ public class FingerprintService extends SystemService {
publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
}
+ /**
+ * Checks for public API invocations to ensure that permissions, etc are granted/correct.
+ */
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean canUseFingerprint(String opPackageName, boolean requireForeground, int uid,
int pid, int userId) {
@@ -358,7 +415,7 @@ public class FingerprintService extends SystemService {
Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied");
return false;
}
- if (requireForeground && !(isForegroundActivity(uid, pid))) {
+ if (requireForeground && !Utils.isForeground(uid, pid)) {
Slog.w(TAG, "Rejecting " + opPackageName + "; not in foreground");
return false;
}
@@ -377,28 +434,5 @@ public class FingerprintService extends SystemService {
return appOpsOk;
}
- private boolean isForegroundActivity(int uid, int pid) {
- try {
- final List<ActivityManager.RunningAppProcessInfo> procs =
- ActivityManager.getService().getRunningAppProcesses();
- if (procs == null) {
- Slog.e(TAG, "Processes null, defaulting to true");
- return true;
- }
-
- int N = procs.size();
- for (int i = 0; i < N; i++) {
- ActivityManager.RunningAppProcessInfo proc = procs.get(i);
- if (proc.pid == pid && proc.uid == uid
- && proc.importance <= IMPORTANCE_FOREGROUND_SERVICE) {
- return true;
- }
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "am.getRunningAppProcesses() failed");
- }
- return false;
- }
-
private native NativeHandle convertSurfaceToNativeHandle(Surface surface);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityDispatcher.java
index 5023c83cd585..7bda33da8126 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityTracker.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/GestureAvailabilityDispatcher.java
@@ -28,7 +28,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* Keeps track of sensor gesture availability (e.g. swipe), and notifies clients when its
* availability changes
*/
-public class GestureAvailabilityTracker {
+public class GestureAvailabilityDispatcher {
private static final String TAG = "GestureAvailabilityTracker";
private final CopyOnWriteArrayList<IFingerprintClientActiveCallback> mClientActiveCallbacks;
@@ -36,7 +36,7 @@ public class GestureAvailabilityTracker {
private boolean mIsActive;
- GestureAvailabilityTracker() {
+ GestureAvailabilityDispatcher() {
mClientActiveCallbacks = new CopyOnWriteArrayList<>();
mActiveSensors = new HashMap<>();
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
index e6e15337d062..5e521d2fe46c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
@@ -16,7 +16,9 @@
package com.android.server.biometrics.sensors.fingerprint;
+import android.annotation.Nullable;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.RemoteException;
import android.util.Slog;
@@ -59,4 +61,26 @@ public class UdfpsHelper {
Slog.e(TAG, "onFingerUp | RemoteException: ", e);
}
}
+
+ static void showUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ if (udfpsOverlayController == null) {
+ return;
+ }
+ try {
+ udfpsOverlayController.showUdfpsOverlay();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when showing the UDFPS overlay", e);
+ }
+ }
+
+ static void hideUdfpsOverlay(@Nullable IUdfpsOverlayController udfpsOverlayController) {
+ if (udfpsOverlayController == null) {
+ return;
+ }
+ try {
+ udfpsOverlayController.hideUdfpsOverlay();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
index 58ab20d8d56d..bcf63dcdd67f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisService.java
@@ -18,17 +18,12 @@ package com.android.server.biometrics.sensors.iris;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import android.annotation.NonNull;
import android.content.Context;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.iris.IIrisService;
-import com.android.server.biometrics.sensors.BiometricServiceBase;
-import com.android.server.biometrics.sensors.BiometricUtils;
-import com.android.server.biometrics.sensors.LockoutTracker;
-import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
-
-import java.util.List;
+import com.android.server.SystemService;
+import com.android.server.biometrics.Utils;
/**
* A service to manage multiple clients that want to access the Iris HAL API.
@@ -36,11 +31,9 @@ import java.util.List;
* iris-related events.
*
* TODO: The vendor is expected to fill in the service. See
- * {@link FingerprintService}
- *
- * @hide
+ * {@link com.android.server.biometrics.sensors.face.FaceService}
*/
-public class IrisService extends BiometricServiceBase {
+public class IrisService extends SystemService {
private static final String TAG = "IrisService";
@@ -50,77 +43,16 @@ public class IrisService extends BiometricServiceBase {
private final class IrisServiceWrapper extends IIrisService.Stub {
@Override // Binder call
public void initializeConfiguration(int sensorId) {
- checkPermission(USE_BIOMETRIC_INTERNAL);
- initializeConfigurationInternal(sensorId);
+ Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
}
}
- /**
- * Initializes the system service.
- * <p>
- * Subclasses must define a single argument constructor that accepts the context
- * and passes it to super.
- * </p>
- *
- * @param context The system server context.
- */
- public IrisService(Context context) {
+ public IrisService(@NonNull Context context) {
super(context);
}
@Override
public void onStart() {
- super.onStart();
publishBinderService(Context.IRIS_SERVICE, new IrisServiceWrapper());
}
-
- @Override
- protected void doTemplateCleanupForUser(int userId) {
-
- }
-
- @Override
- protected String getTag() {
- return TAG;
- }
-
- @Override
- protected Object getDaemon() {
- return null;
- }
-
- @Override
- protected BiometricUtils getBiometricUtils() {
- return null;
- }
-
- @Override
- protected boolean hasReachedEnrollmentLimit(int userId) {
- return false;
- }
-
- @Override
- protected void updateActiveGroup(int userId) {
-
- }
-
- @Override
- protected boolean hasEnrolledBiometrics(int userId) {
- return false;
- }
-
- @Override
- protected String getManageBiometricPermission() {
- return null;
- }
-
- @Override
- protected List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(int userId) {
- return null;
- }
-
- @Override
- protected int statsModality() {
- return BiometricsProtoEnums.MODALITY_IRIS;
- }
}
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index b279b370c611..ed3a223b5dd7 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -400,7 +400,7 @@ public class ClipboardService extends SystemService {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId)
+ intendingUid, intendingUserId, false)
|| isDeviceLocked(intendingUserId)) {
return null;
}
@@ -416,7 +416,7 @@ public class ClipboardService extends SystemService {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId)
+ intendingUid, intendingUserId, false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
@@ -450,7 +450,7 @@ public class ClipboardService extends SystemService {
final int intendingUid = getIntendingUid(callingPackage, userId);
final int intendingUserId = UserHandle.getUserId(intendingUid);
if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage,
- intendingUid, intendingUserId)
+ intendingUid, intendingUserId, false)
|| isDeviceLocked(intendingUserId)) {
return false;
}
@@ -740,14 +740,21 @@ public class ClipboardService extends SystemService {
private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
@UserIdInt int userId) {
- // Check the AppOp.
- if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return false;
- }
+ return clipboardAccessAllowed(op, callingPackage, uid, userId, true);
+ }
+
+ private boolean clipboardAccessAllowed(int op, String callingPackage, int uid,
+ @UserIdInt int userId, boolean shouldNoteOp) {
+
+ boolean allowed = false;
+
+ // First, verify package ownership to ensure use below is safe.
+ mAppOps.checkPackage(uid, callingPackage);
+
// Shell can access the clipboard for testing purposes.
if (mPm.checkPermission(android.Manifest.permission.READ_CLIPBOARD_IN_BACKGROUND,
callingPackage) == PackageManager.PERMISSION_GRANTED) {
- return true;
+ allowed = true;
}
// The default IME is always allowed to access the clipboard.
String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(),
@@ -755,7 +762,7 @@ public class ClipboardService extends SystemService {
if (!TextUtils.isEmpty(defaultIme)) {
final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName();
if (imePkg.equals(callingPackage)) {
- return true;
+ allowed = true;
}
}
@@ -766,8 +773,10 @@ public class ClipboardService extends SystemService {
// at the same time. e.x. SystemUI. It needs to check the window focus of
// Binder.getCallingUid(). Without checking, the user X can't copy any thing from
// INTERNAL_SYSTEM_WINDOW to the other applications.
- boolean allowed = mWm.isUidFocused(uid)
- || isInternalSysWindowAppWithWindowFocus(callingPackage);
+ if (!allowed) {
+ allowed = mWm.isUidFocused(uid)
+ || isInternalSysWindowAppWithWindowFocus(callingPackage);
+ }
if (!allowed && mContentCaptureInternal != null) {
// ...or the Content Capture Service
// The uid parameter of mContentCaptureInternal.isContentCaptureServiceForUser
@@ -786,17 +795,28 @@ public class ClipboardService extends SystemService {
// userId must pass intending userId. i.e. user#10.
allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(uid, userId);
}
- if (!allowed) {
- Slog.e(TAG, "Denying clipboard access to " + callingPackage
- + ", application is not in focus neither is a system service for "
- + "user " + userId);
- }
- return allowed;
+ break;
case AppOpsManager.OP_WRITE_CLIPBOARD:
// Writing is allowed without focus.
- return true;
+ allowed = true;
+ break;
default:
throw new IllegalArgumentException("Unknown clipboard appop " + op);
}
+ if (!allowed) {
+ Slog.e(TAG, "Denying clipboard access to " + callingPackage
+ + ", application is not in focus nor is it a system service for "
+ + "user " + userId);
+ return false;
+ }
+ // Finally, check the app op.
+ int appOpsResult;
+ if (shouldNoteOp) {
+ appOpsResult = mAppOps.noteOp(op, uid, callingPackage);
+ } else {
+ appOpsResult = mAppOps.checkOp(op, uid, callingPackage);
+ }
+
+ return appOpsResult == AppOpsManager.MODE_ALLOWED;
}
}
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index f6ce2dc68b99..de302fc01f2d 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -196,13 +196,7 @@ public class PacManager {
mPacUrl = Uri.EMPTY;
mCurrentPac = null;
if (mProxyService != null) {
- try {
- mProxyService.stopPacSystem();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to stop PAC service", e);
- } finally {
- unbind();
- }
+ unbind();
}
}
return DO_SEND_BROADCAST;
@@ -327,11 +321,6 @@ public class PacManager {
if (mProxyService == null) {
Log.e(TAG, "No proxy service");
} else {
- try {
- mProxyService.startPacSystem();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e);
- }
mNetThreadHandler.post(mPacDownloader);
}
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index f812a05fd06f..26cc3ee165f1 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -163,7 +163,7 @@ public class ProxyTracker {
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyInfo(pacFileUrl);
+ proxyProperties = new ProxyInfo(Uri.parse(pacFileUrl));
} else {
proxyProperties = new ProxyInfo(host, port, exclList);
}
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
index 8ed32f09e23a..6669b8cec143 100644
--- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -26,9 +26,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.util.Slog;
-import com.android.server.SystemService;
-import java.util.List;
+import com.android.server.SystemService;
/** This class provides a system service that monitors media resource usage. */
public class MediaResourceMonitorService extends SystemService {
@@ -62,8 +61,7 @@ public class MediaResourceMonitorService extends SystemService {
if (pkgNames == null) {
return;
}
- UserManager manager = (UserManager) getContext().getSystemService(
- Context.USER_SERVICE);
+ UserManager manager = getContext().getSystemService(UserManager.class);
int[] userIds = manager.getEnabledProfileIds(ActivityManager.getCurrentUser());
if (userIds == null || userIds.length == 0) {
return;
@@ -81,15 +79,11 @@ public class MediaResourceMonitorService extends SystemService {
}
private String[] getPackageNamesFromPid(int pid) {
- try {
- for (ActivityManager.RunningAppProcessInfo proc :
- ActivityManager.getService().getRunningAppProcesses()) {
- if (proc.pid == pid) {
- return proc.pkgList;
- }
+ ActivityManager manager = getContext().getSystemService(ActivityManager.class);
+ for (ActivityManager.RunningAppProcessInfo proc : manager.getRunningAppProcesses()) {
+ if (proc.pid == pid) {
+ return proc.pkgList;
}
- } catch (RemoteException e) {
- Slog.w(TAG, "ActivityManager.getRunningAppProcesses() failed");
}
return null;
}
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index e3e02e32ad50..f0bf5c0975f2 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -24,6 +24,7 @@ import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
+import android.net.Uri;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
@@ -372,7 +373,7 @@ public class IpConfigStore {
config.httpProxy = proxyInfo;
break;
case PAC:
- ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
+ ProxyInfo proxyPacProperties = new ProxyInfo(Uri.parse(pacFileUrl));
config.proxySettings = proxySettings;
config.httpProxy = proxyPacProperties;
break;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 87f0fb14ee33..ea047888caff 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3910,11 +3910,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateRulesForAppIdleParoleUL() {
final boolean paroled = mAppStandby.isInParole();
final boolean enableChain = !paroled;
- enableFirewallChainUL(FIREWALL_CHAIN_STANDBY, enableChain);
int ruleCount = mUidFirewallStandbyRules.size();
+ final SparseIntArray blockedUids = new SparseIntArray();
for (int i = 0; i < ruleCount; i++) {
final int uid = mUidFirewallStandbyRules.keyAt(i);
+ if (!isUidValidForBlacklistRulesUL(uid)) {
+ continue;
+ }
int oldRules = mUidRules.get(uid);
if (enableChain) {
// Chain wasn't enabled before and the other power-related
@@ -3926,13 +3929,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// Skip if it had no restrictions to begin with
if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
}
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ final boolean isUidIdle = !paroled && isUidIdle(uid);
+ if (isUidIdle && !mPowerSaveTempWhitelistAppIds.get(UserHandle.getAppId(uid))
+ && !isUidForegroundOnRestrictPowerUL(uid)) {
+ mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DENY);
+ blockedUids.put(uid, FIREWALL_RULE_DENY);
+ } else {
+ mUidFirewallStandbyRules.put(uid, FIREWALL_RULE_DEFAULT);
+ }
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules,
+ isUidIdle);
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newUidRules);
}
}
+ setUidFirewallRulesUL(FIREWALL_CHAIN_STANDBY, blockedUids,
+ enableChain ? CHAIN_TOGGLE_ENABLE : CHAIN_TOGGLE_DISABLE);
}
/**
@@ -4400,7 +4414,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private void updateRulesForPowerRestrictionsUL(int uid) {
final int oldUidRules = mUidRules.get(uid, RULE_NONE);
- final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules, false);
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldUidRules,
+ isUidIdle(uid));
if (newUidRules == RULE_NONE) {
mUidRules.delete(uid);
@@ -4414,33 +4429,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*
* @param uid the uid of the app to update rules for
* @param oldUidRules the current rules for the uid, in order to determine if there's a change
- * @param paroled whether to ignore idle state of apps and only look at other restrictions
+ * @param isUidIdle whether uid is idle or not
*
* @return the new computed rules for the uid
*/
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean paroled) {
+ private int updateRulesForPowerRestrictionsUL(int uid, int oldUidRules, boolean isUidIdle) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
"updateRulesForPowerRestrictionsUL: " + uid + "/" + oldUidRules + "/"
- + (paroled ? "P" : "-"));
+ + (isUidIdle ? "I" : "-"));
}
try {
- return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, paroled);
+ return updateRulesForPowerRestrictionsULInner(uid, oldUidRules, isUidIdle);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
@GuardedBy("mUidRulesFirstLock")
- private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules, boolean paroled) {
+ private int updateRulesForPowerRestrictionsULInner(int uid, int oldUidRules,
+ boolean isUidIdle) {
if (!isUidValidForBlacklistRulesUL(uid)) {
if (LOGD) Slog.d(TAG, "no need to update restrict power rules for uid " + uid);
return RULE_NONE;
}
- final boolean isIdle = !paroled && isUidIdle(uid);
- final boolean restrictMode = isIdle || mRestrictPower || mDeviceIdleMode;
+ final boolean restrictMode = isUidIdle || mRestrictPower || mDeviceIdleMode;
final boolean isForeground = isUidForegroundOnRestrictPowerUL(uid);
final boolean isWhitelisted = isWhitelistedFromPowerSaveUL(uid, mDeviceIdleMode);
@@ -4463,7 +4478,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (LOGV) {
Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")"
- + ", isIdle: " + isIdle
+ + ", isIdle: " + isUidIdle
+ ", mRestrictPower: " + mRestrictPower
+ ", mDeviceIdleMode: " + mDeviceIdleMode
+ ", isForeground=" + isForeground
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index db553ee79555..0575ac6315a1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -16,12 +16,14 @@
package com.android.server.net;
+import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA;
import static android.net.NetworkTemplate.getCollapsedRatType;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Looper;
import android.telephony.Annotation;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -196,7 +198,18 @@ public class NetworkStatsSubscriptionsMonitor extends
@Override
public void onServiceStateChanged(@NonNull ServiceState ss) {
- final int networkType = ss.getDataNetworkType();
+ // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony
+ // would report RAT = 5G_NR.
+ // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and
+ // network allocates a secondary 5G cell so telephony reports RAT = LTE along with
+ // NR state as connected. In such case, attributes the data usage to NR.
+ // See b/160727498.
+ final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE
+ || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA)
+ && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED;
+
+ final int networkType =
+ (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType());
final int collapsedRatType = getCollapsedRatType(networkType);
if (collapsedRatType == mLastCollapsedRatType) return;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 592db83b8721..249b6801758b 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -563,76 +563,85 @@ public abstract class ApexManager {
@Override
@Nullable
- public PackageInfo getPackageInfo(String packageName,
- @PackageInfoFlags int flags) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
- boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!packageInfo.packageName.equals(packageName)) {
- continue;
- }
- if ((matchActive && isActive(packageInfo))
- || (matchFactory && isFactory(packageInfo))) {
- return packageInfo;
+ public PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
+ boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (!packageInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if ((matchActive && isActive(packageInfo))
+ || (matchFactory && isFactory(packageInfo))) {
+ return packageInfo;
+ }
}
+ return null;
}
- return null;
}
@Override
List<PackageInfo> getActivePackages() {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> activePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isActive(packageInfo)) {
- activePackages.add(packageInfo);
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> activePackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (isActive(packageInfo)) {
+ activePackages.add(packageInfo);
+ }
}
+ return activePackages;
}
- return activePackages;
}
@Override
List<PackageInfo> getFactoryPackages() {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> factoryPackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (isFactory(packageInfo)) {
- factoryPackages.add(packageInfo);
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> factoryPackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (isFactory(packageInfo)) {
+ factoryPackages.add(packageInfo);
+ }
}
+ return factoryPackages;
}
- return factoryPackages;
}
@Override
List<PackageInfo> getInactivePackages() {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<PackageInfo> inactivePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (!isActive(packageInfo)) {
- inactivePackages.add(packageInfo);
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ final List<PackageInfo> inactivePackages = new ArrayList<>();
+ for (int i = 0; i < mAllPackagesCache.size(); i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (!isActive(packageInfo)) {
+ inactivePackages.add(packageInfo);
+ }
}
+ return inactivePackages;
}
- return inactivePackages;
}
@Override
boolean isApexPackage(String packageName) {
if (!isApexSupported()) return false;
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final PackageInfo packageInfo = mAllPackagesCache.get(i);
- if (packageInfo.packageName.equals(packageName)) {
- return true;
+ synchronized (mLock) {
+ Preconditions.checkState(mAllPackagesCache != null,
+ "APEX packages have not been scanned");
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
+ if (packageInfo.packageName.equals(packageName)) {
+ return true;
+ }
}
}
return false;
@@ -640,14 +649,11 @@ public abstract class ApexManager {
@Override
@Nullable
- public String getActiveApexPackageNameContainingPackage(
- @NonNull AndroidPackage containedPackage) {
- Preconditions.checkState(mPackageNameToApexModuleName != null,
- "APEX packages have not been scanned");
-
+ public String getActiveApexPackageNameContainingPackage(AndroidPackage containedPackage) {
Objects.requireNonNull(containedPackage);
-
synchronized (mLock) {
+ Preconditions.checkState(mPackageNameToApexModuleName != null,
+ "APEX packages have not been scanned");
int numApksInApex = mApksInApex.size();
for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
if (mApksInApex.valueAt(apkInApexNum).contains(
@@ -982,9 +988,11 @@ public abstract class ApexManager {
}
ipw.decreaseIndent();
ipw.println();
- if (mAllPackagesCache == null) {
- ipw.println("APEX packages have not been scanned");
- return;
+ synchronized (mLock) {
+ if (mAllPackagesCache == null) {
+ ipw.println("APEX packages have not been scanned");
+ return;
+ }
}
ipw.println("Active APEX packages:");
dumpFromPackagesCache(getActivePackages(), packageName, ipw);
@@ -1023,12 +1031,17 @@ public abstract class ApexManager {
if (files != null) {
for (File file : files) {
if (file.isDirectory() && !file.getName().contains("@")) {
+ boolean skip = false;
for (String skipDir : skipDirs) {
if (file.getName().equals(skipDir)) {
- continue;
+ skip = true;
+ break;
}
}
- result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
+ if (!skip) {
+ result.add(
+ new ActiveApexInfo(file, Environment.getRootDirectory()));
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index ca16d5730f78..00cb22e9d4b5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -403,6 +403,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private boolean mVerityFound;
+ @GuardedBy("mLock")
private boolean mDataLoaderFinished = false;
@GuardedBy("mLock")
@@ -458,8 +459,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final int returnCode = args.argi1;
args.recycle();
+ final boolean showNotification;
+ synchronized (mLock) {
+ showNotification = isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked();
+ }
sendOnPackageInstalled(mContext, statusReceiver, sessionId,
- isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
+ showNotification, userId,
packageName, returnCode, message, extras);
break;
@@ -887,6 +892,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return markerName;
}
+ @GuardedBy("mLock")
private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
try {
final File target = new File(stageDir, getRemoveMarkerName(splitName));
@@ -1057,6 +1063,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ @GuardedBy("mLock")
private ParcelFileDescriptor openReadInternalLocked(String name) throws IOException {
try {
if (!FileUtils.isValidExtFilename(name)) {
@@ -1118,7 +1125,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
- + mParentSessionId + " and may not be committed directly.");
+ + getParentSessionId() + " and may not be committed directly.");
}
if (!markAsSealed(statusReceiver, forTransfer)) {
@@ -1589,12 +1596,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onStorageUnhealthy() {
- if (TextUtils.isEmpty(mPackageName)) {
+ final String packageName = getPackageName();
+ if (TextUtils.isEmpty(packageName)) {
// The package has not been installed.
return;
}
final PackageManagerService packageManagerService = mPm;
- final String packageName = mPackageName;
mHandler.post(() -> {
if (packageManagerService.deletePackageX(packageName,
PackageManager.VERSION_CODE_HIGHEST, UserHandle.USER_SYSTEM,
@@ -1686,7 +1693,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void handleInstall() {
- if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
+ final boolean needsLogging;
+ synchronized (mLock) {
+ needsLogging = isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked();
+ }
+ if (needsLogging) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
.setAdmin(mInstallSource.installerPackageName)
@@ -1929,19 +1940,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Skip logging the side-loaded app installations, as those are private and aren't reported
// anywhere; app stores already have a record of the installation and that's why reporting
// it here is fine
+ final String packageName = getPackageName();
final String packageNameToLog =
- (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? mPackageName : "";
+ (params.installFlags & PackageManager.INSTALL_FROM_ADB) == 0 ? packageName : "";
final long currentTimestamp = System.currentTimeMillis();
FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLER_V2_REPORTED,
isIncrementalInstallation(),
packageNameToLog,
currentTimestamp - createdMillis,
returnCode,
- getApksSize());
+ getApksSize(packageName));
}
- private long getApksSize() {
- final PackageSetting ps = mPm.getPackageSetting(mPackageName);
+ private long getApksSize(String packageName) {
+ final PackageSetting ps = mPm.getPackageSetting(packageName);
if (ps == null) {
return 0;
}
@@ -2017,7 +2029,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetFile = new File(stageDir, targetName);
- resolveAndStageFile(addedFile, targetFile);
+ resolveAndStageFileLocked(addedFile, targetFile);
mResolvedBaseFile = targetFile;
// Populate package name of the apex session
@@ -2133,7 +2145,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetFile = new File(stageDir, targetName);
- resolveAndStageFile(addedFile, targetFile);
+ resolveAndStageFileLocked(addedFile, targetFile);
// Base is coming from session
if (apk.splitName == null) {
@@ -2150,7 +2162,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final File targetDexMetadataFile = new File(stageDir,
DexMetadataHelper.buildDexMetadataPathForApk(targetName));
- resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
+ resolveAndStageFileLocked(dexMetadataFile, targetDexMetadataFile);
}
}
@@ -2230,12 +2242,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Inherit base if not overridden
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
- resolveInheritedFile(mResolvedBaseFile);
+ resolveInheritedFileLocked(mResolvedBaseFile);
// Inherit the dex metadata if present.
final File baseDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(mResolvedBaseFile);
if (baseDexMetadataFile != null) {
- resolveInheritedFile(baseDexMetadataFile);
+ resolveInheritedFileLocked(baseDexMetadataFile);
}
baseApk = existingBase;
}
@@ -2247,12 +2259,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final File splitFile = new File(existing.splitCodePaths[i]);
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
- resolveInheritedFile(splitFile);
+ resolveInheritedFileLocked(splitFile);
// Inherit the dex metadata if present.
final File splitDexMetadataFile =
DexMetadataHelper.findDexMetadataForFile(splitFile);
if (splitDexMetadataFile != null) {
- resolveInheritedFile(splitDexMetadataFile);
+ resolveInheritedFileLocked(splitDexMetadataFile);
}
}
}
@@ -2353,7 +2365,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- private void resolveAndStageFile(File origFile, File targetFile)
+ @GuardedBy("mLock")
+ private void resolveAndStageFileLocked(File origFile, File targetFile)
throws PackageManagerException {
mResolvedStagedFiles.add(targetFile);
maybeRenameFile(origFile, targetFile);
@@ -2386,7 +2399,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mResolvedStagedFiles.add(stagedSignature);
}
- private void resolveInheritedFile(File origFile) {
+ @GuardedBy("mLock")
+ private void resolveInheritedFileLocked(File origFile) {
mResolvedInheritedFiles.add(origFile);
// Inherit the fsverity signature file if present.
@@ -2577,7 +2591,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
void setPermissionsResult(boolean accepted) {
- if (!mSealed) {
+ if (!isSealed()) {
throw new SecurityException("Must be sealed to accept permissions");
}
@@ -2653,7 +2667,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
- + mParentSessionId + " and may not be abandoned directly.");
+ + getParentSessionId() + " and may not be abandoned directly.");
}
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
@@ -2823,7 +2837,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return;
}
- if (mDestroyed || mDataLoaderFinished) {
+ final boolean isDestroyedOrDataLoaderFinished;
+ synchronized (mLock) {
+ isDestroyedOrDataLoaderFinished = mDestroyed || mDataLoaderFinished;
+ }
+ if (isDestroyedOrDataLoaderFinished) {
switch (status) {
case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
onStorageUnhealthy();
@@ -2835,7 +2853,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
try {
IDataLoader dataLoader = dataLoaderManager.getDataLoader(dataLoaderId);
if (dataLoader == null) {
- mDataLoaderFinished = true;
+ synchronized (mLock) {
+ mDataLoaderFinished = true;
+ }
dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failure to obtain data loader");
return;
@@ -2868,10 +2888,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
break;
}
case IDataLoaderStatusListener.DATA_LOADER_IMAGE_READY: {
- mDataLoaderFinished = true;
+ synchronized (mLock) {
+ mDataLoaderFinished = true;
+ }
if (hasParentSessionId()) {
mSessionProvider.getSession(
- mParentSessionId).dispatchStreamValidateAndCommit();
+ getParentSessionId()).dispatchStreamValidateAndCommit();
} else {
dispatchStreamValidateAndCommit();
}
@@ -2881,7 +2903,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
break;
}
case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
- mDataLoaderFinished = true;
+ synchronized (mLock) {
+ mDataLoaderFinished = true;
+ }
dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to prepare image.");
if (manualStartAndDestroy) {
@@ -2895,7 +2919,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
break;
}
case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE:
- mDataLoaderFinished = true;
+ synchronized (mLock) {
+ mDataLoaderFinished = true;
+ }
dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"DataLoader reported unrecoverable failure.");
break;
@@ -2919,7 +2945,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() {
@Override
public void onHealthStatus(int storageId, int status) {
- if (mDestroyed || mDataLoaderFinished) {
+ final boolean isDestroyedOrDataLoaderFinished;
+ synchronized (mLock) {
+ isDestroyedOrDataLoaderFinished = mDestroyed || mDataLoaderFinished;
+ }
+ if (isDestroyedOrDataLoaderFinished) {
// App's installed.
switch (status) {
case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
@@ -2941,7 +2971,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// fallthrough
case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY:
// Even ADB installation can't wait for missing pages for too long.
- mDataLoaderFinished = true;
+ synchronized (mLock) {
+ mDataLoaderFinished = true;
+ }
dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Image is missing pages required for installation.");
break;
@@ -2984,13 +3016,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return EMPTY_CHILD_SESSION_ARRAY;
}
+ private boolean canBeAddedAsChild(int parentCandidate) {
+ synchronized (mLock) {
+ return (!hasParentSessionId() || mParentSessionId == parentCandidate)
+ && !mCommitted && !mDestroyed;
+ }
+ }
+
@Override
public void addChildSessionId(int childSessionId) {
final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
- if (childSession == null
- || (childSession.hasParentSessionId() && childSession.mParentSessionId != sessionId)
- || childSession.mCommitted
- || childSession.mDestroyed) {
+ if (childSession == null || !childSession.canBeAddedAsChild(sessionId)) {
throw new IllegalStateException("Unable to add child session " + childSessionId
+ " as it does not exist or is in an invalid state.");
}
@@ -3039,12 +3075,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
boolean hasParentSessionId() {
- return mParentSessionId != SessionInfo.INVALID_ID;
+ synchronized (mLock) {
+ return mParentSessionId != SessionInfo.INVALID_ID;
+ }
}
@Override
public int getParentSessionId() {
- return mParentSessionId;
+ synchronized (mLock) {
+ return mParentSessionId;
+ }
}
private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
@@ -3134,27 +3174,37 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
/** {@hide} */
boolean isStagedSessionReady() {
- return mStagedSessionReady;
+ synchronized (mLock) {
+ return mStagedSessionReady;
+ }
}
/** {@hide} */
boolean isStagedSessionApplied() {
- return mStagedSessionApplied;
+ synchronized (mLock) {
+ return mStagedSessionApplied;
+ }
}
/** {@hide} */
boolean isStagedSessionFailed() {
- return mStagedSessionFailed;
+ synchronized (mLock) {
+ return mStagedSessionFailed;
+ }
}
/** {@hide} */
@StagedSessionErrorCode int getStagedSessionErrorCode() {
- return mStagedSessionErrorCode;
+ synchronized (mLock) {
+ return mStagedSessionErrorCode;
+ }
}
/** {@hide} */
String getStagedSessionErrorMessage() {
- return mStagedSessionErrorMessage;
+ synchronized (mLock) {
+ return mStagedSessionErrorMessage;
+ }
}
private void destroyInternal() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9f3db704253e..bd12fd5f5d9a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6490,7 +6490,7 @@ public class PackageManagerService extends IPackageManager.Stub
intent, resolvedType, flags, query, 0, false, true, false, userId);
// Add the new activity as the last chosen for this filter
addPreferredActivityInternal(filter, match, null, activity, false, userId,
- "Setting last chosen");
+ "Setting last chosen", false);
}
@Override
@@ -7158,8 +7158,9 @@ public class PackageManagerService extends IPackageManager.Stub
&& ((!matchInstantApp && !isCallerInstantApp && isTargetInstantApp)
|| (matchVisibleToInstantAppOnly && isCallerInstantApp
&& isTargetHiddenFromInstantApp));
- final boolean blockNormalResolution = !isTargetInstantApp && !isCallerInstantApp
- && shouldFilterApplicationLocked(
+ final boolean blockNormalResolution =
+ !resolveForStart && !isTargetInstantApp && !isCallerInstantApp
+ && shouldFilterApplicationLocked(
getPackageSettingInternal(ai.applicationInfo.packageName,
Process.SYSTEM_UID), filterCallingUid, userId);
if (!blockInstantResolution && !blockNormalResolution) {
@@ -7252,8 +7253,8 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageSetting setting =
getPackageSettingInternal(pkgName, Process.SYSTEM_UID);
result = null;
- if (setting != null && setting.pkg != null
- && !shouldFilterApplicationLocked(setting, filterCallingUid, userId)) {
+ if (setting != null && setting.pkg != null && (resolveForStart
+ || !shouldFilterApplicationLocked(setting, filterCallingUid, userId))) {
result = filterIfNotSystemUser(mComponentResolver.queryActivities(
intent, resolvedType, flags, setting.pkg.getActivities(), userId),
userId);
@@ -19609,14 +19610,14 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
+ ComponentName[] set, ComponentName activity, int userId, boolean removeExisting) {
addPreferredActivityInternal(filter, match, set, activity, true, userId,
- "Adding preferred");
+ "Adding preferred", removeExisting);
}
private void addPreferredActivityInternal(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, boolean always, int userId,
- String opname) {
+ String opname, boolean removeExisting) {
// writer
int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
@@ -19644,6 +19645,10 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
final PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
+ final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
+ if (removeExisting && existing != null) {
+ removeFiltersLocked(pir, filter, existing);
+ }
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
scheduleWritePackageRestrictionsLocked(userId);
}
@@ -19743,24 +19748,28 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
if (existing != null) {
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, existing.size() + " existing preferred matches for:");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- }
- for (int i = existing.size() - 1; i >= 0; --i) {
- final PreferredActivity pa = existing.get(i);
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Removing existing preferred activity "
- + pa.mPref.mComponent + ":");
- pa.dump(new LogPrinter(Log.INFO, TAG), " ");
- }
- pir.removeFilter(pa);
- }
+ removeFiltersLocked(pir, filter, existing);
}
}
}
addPreferredActivityInternal(filter, match, set, activity, true, userId,
- "Replacing preferred");
+ "Replacing preferred", false);
+ }
+
+ private void removeFiltersLocked(@NonNull PreferredIntentResolver pir,
+ @NonNull IntentFilter filter, @NonNull List<PreferredActivity> existing) {
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, existing.size() + " preferred matches for:");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
+ for (int i = existing.size() - 1; i >= 0; --i) {
+ final PreferredActivity pa = existing.get(i);
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Removing preferred activity " + pa.mPref.mComponent + ":");
+ pa.dump(new LogPrinter(Log.INFO, TAG), " ");
+ }
+ pir.removeFilter(pa);
+ }
}
@Override
@@ -25545,7 +25554,8 @@ public class PackageManagerService extends IPackageManager.Stub
private void applyMimeGroupChanges(String packageName, String mimeGroup) {
if (mComponentResolver.updateMimeGroup(packageName, mimeGroup)) {
- clearPackagePreferredActivities(packageName, UserHandle.USER_ALL);
+ Binder.withCleanCallingIdentity(() ->
+ clearPackagePreferredActivities(packageName, UserHandle.USER_ALL));
}
mPmInternal.writeSettings(false);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 0472b821d3cc..13b927e7d9f4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1407,7 +1407,7 @@ public final class Settings {
if (pa.mPref.getParseError() == null) {
final PreferredIntentResolver resolver = editPreferredActivitiesLPw(userId);
ArrayList<PreferredActivity> pal = resolver.findFilters(pa);
- if (pal == null || pal.size() == 0) {
+ if (pal == null || pal.size() == 0 || pa.mPref.mAlways) {
resolver.addFilter(pa);
}
} else {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 14da9aa14470..616e5d13f990 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -738,7 +738,6 @@ public class StagingManager {
PackageInstaller.SessionParams params = originalSession.params.copy();
params.isStaged = false;
params.installFlags |= PackageManager.INSTALL_STAGED;
- // TODO(b/129744602): use the userid from the original session.
if (preReboot) {
params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
params.installFlags |= PackageManager.INSTALL_DRY_RUN;
@@ -748,7 +747,7 @@ public class StagingManager {
try {
int apkSessionId = mPi.createSession(
params, originalSession.getInstallerPackageName(),
- originalSession.getInstallerAttributionTag(), 0 /* UserHandle.SYSTEM */);
+ originalSession.getInstallerAttributionTag(), originalSession.userId);
PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
apkSession.open();
for (int i = 0, size = apkFilePaths.size(); i < size; i++) {
@@ -806,10 +805,9 @@ public class StagingManager {
if (preReboot) {
params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
}
- // TODO(b/129744602): use the userid from the original session.
final int apkParentSessionId = mPi.createSession(
params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
- 0 /* UserHandle.SYSTEM */);
+ session.userId);
final PackageInstallerSession apkParentSession = mPi.getSession(apkParentSessionId);
try {
apkParentSession.open();
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 9963cf7e212d..bc7554c54eb0 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -4224,6 +4224,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
revokePermissionFromPackageForUser(p.getPackageName(),
bp.getName(), true, userId, callback));
}
+ } else {
+ mPackageManagerInt.forEachPackage(p -> {
+ PackageSetting ps = mPackageManagerInt.getPackageSetting(
+ p.getPackageName());
+ if (ps == null) {
+ return;
+ }
+ PermissionsState permissionsState = ps.getPermissionsState();
+ if (permissionsState.getInstallPermissionState(bp.getName()) != null) {
+ permissionsState.revokeInstallPermission(bp);
+ permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL,
+ MASK_PERMISSION_FLAGS_ALL, 0);
+ }
+ });
}
it.remove();
}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 710185db7fbd..6e48cbbb3b5b 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -140,6 +140,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
@IntDef({NAV_BAR_LEFT, NAV_BAR_RIGHT, NAV_BAR_BOTTOM})
@interface NavigationBarPosition {}
+ @Retention(SOURCE)
+ @IntDef({ALT_BAR_UNKNOWN, ALT_BAR_LEFT, ALT_BAR_RIGHT, ALT_BAR_BOTTOM, ALT_BAR_TOP})
+ @interface AltBarPosition {}
+
/**
* Pass this event to the user / app. To be returned from
* {@link #interceptKeyBeforeQueueing}.
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
index 72f8027e664f..761858ccd238 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java
@@ -192,10 +192,7 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 {
}
private static RuntimeException handleException(RuntimeException e) {
- // TODO(b/160169016): There is currently no other way to distinguish dead object from other
- // exceptions.
- if (e.getCause() instanceof RemoteException &&
- e.getCause().getMessage().equals("HwBinder Error: (-32)")) {
+ if (e.getCause() instanceof DeadObjectException) {
// Server is dead, no need to reboot.
Log.e(TAG, "HAL died");
} else {
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index dbdef2368c7c..f74cd611e9d0 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -39,8 +39,6 @@ import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
import static android.util.MathUtils.constrain;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
-import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_TRUNCATE_TIMESTAMP;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC;
import static com.android.internal.util.FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
@@ -1100,25 +1098,21 @@ public class StatsPullAtomService extends SystemService {
final NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
for (int j = 0; j < size; j++) {
statsExt.stats.getValues(j, entry);
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- switch (atomTag) {
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER:
- case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG:
- e.addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true);
- break;
- default:
- }
- e.writeInt(entry.uid);
- e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
+ StatsEvent statsEvent;
+
if (statsExt.slicedByFgbg) {
- e.writeInt(entry.set);
+ // MobileBytesTransferByFgBg atom or WifiBytesTransferByFgBg atom.
+ statsEvent = FrameworkStatsLog.buildStatsEvent(
+ atomTag, entry.uid,
+ (entry.set > 0), entry.rxBytes, entry.rxPackets, entry.txBytes,
+ entry.txPackets);
+ } else {
+ // MobileBytesTransfer atom or WifiBytesTransfer atom.
+ statsEvent = FrameworkStatsLog.buildStatsEvent(
+ atomTag, entry.uid, entry.rxBytes,
+ entry.rxPackets, entry.txBytes, entry.txPackets);
}
- e.writeLong(entry.rxBytes);
- e.writeLong(entry.rxPackets);
- e.writeLong(entry.txBytes);
- e.writeLong(entry.txPackets);
- ret.add(e.build());
+ ret.add(statsEvent);
}
}
@@ -1127,46 +1121,38 @@ public class StatsPullAtomService extends SystemService {
final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
for (int i = 0; i < statsExt.stats.size(); i++) {
statsExt.stats.getValues(i, entry);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED)
- .addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true)
- .writeInt(entry.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeBoolean(entry.metered == NetworkStats.METERED_YES)
- .writeInt(entry.tag)
- .writeLong(entry.rxBytes)
- .writeLong(entry.rxPackets)
- .writeLong(entry.txBytes)
- .writeLong(entry.txPackets)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED, entry.uid,
+ entry.metered == NetworkStats.METERED_YES, entry.tag, entry.rxBytes,
+ entry.rxPackets, entry.txBytes, entry.txPackets));
}
}
private void addDataUsageBytesTransferAtoms(@NonNull NetworkStatsExt statsExt,
@NonNull List<StatsEvent> pulledData) {
+
+ // Workaround for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}.
+ // 5G NSA mode means the primary cell is LTE with a secondary connection to an
+ // NR cell. To mitigate risk, NetworkStats is currently storing this state as
+ // a fake RAT type rather than storing the boolean separately.
+ final boolean is5GNsa = statsExt.ratType == NetworkTemplate.NETWORK_TYPE_5G_NSA;
+ // Report NR connected in 5G non-standalone mode, or if the RAT type is NR to begin with.
+ final boolean isNR = is5GNsa || statsExt.ratType == TelephonyManager.NETWORK_TYPE_NR;
+
final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling
for (int i = 0; i < statsExt.stats.size(); i++) {
statsExt.stats.getValues(i, entry);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER)
- .addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true)
- .writeInt(entry.set)
- .writeLong(entry.rxBytes)
- .writeLong(entry.rxPackets)
- .writeLong(entry.txBytes)
- .writeLong(entry.txPackets)
- .writeInt(statsExt.ratType)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER, entry.set, entry.rxBytes,
+ entry.rxPackets, entry.txBytes, entry.txPackets,
+ is5GNsa ? TelephonyManager.NETWORK_TYPE_LTE : statsExt.ratType,
// Fill information about subscription, these cannot be null since invalid data
// would be filtered when adding into subInfo list.
- .writeString(statsExt.subInfo.mcc)
- .writeString(statsExt.subInfo.mnc)
- .writeInt(statsExt.subInfo.carrierId)
- .writeInt(statsExt.subInfo.isOpportunistic
+ statsExt.subInfo.mcc, statsExt.subInfo.mnc, statsExt.subInfo.carrierId,
+ statsExt.subInfo.isOpportunistic
? DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__OPPORTUNISTIC
- : DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC)
- .build();
- pulledData.add(e);
+ : DATA_USAGE_BYTES_TRANSFER__OPPORTUNISTIC_DATA_SUB__NOT_OPPORTUNISTIC,
+ isNR));
}
}
@@ -1427,14 +1413,8 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
for (UidTraffic traffic : info.getUidTraffic()) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(traffic.getUid())
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeLong(traffic.getRxBytes())
- .writeLong(traffic.getTxBytes())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, traffic.getUid(), traffic.getRxBytes(), traffic.getTxBytes()));
}
return StatsManager.PULL_SUCCESS;
}
@@ -1455,14 +1435,8 @@ public class StatsPullAtomService extends SystemService {
for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
String name = ent.getKey();
KernelWakelockStats.Entry kws = ent.getValue();
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeString(name)
- .writeInt(kws.mCount)
- .writeInt(kws.mVersion)
- .writeLong(kws.mTotalTime)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, name, kws.mCount, kws.mVersion, kws.mTotalTime));
}
return StatsManager.PULL_SUCCESS;
}
@@ -1485,13 +1459,8 @@ public class StatsPullAtomService extends SystemService {
long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute();
if (clusterTimeMs != null) {
for (int speed = clusterTimeMs.length - 1; speed >= 0; --speed) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(cluster)
- .writeInt(speed)
- .writeLong(clusterTimeMs[speed])
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, cluster, speed, clusterTimeMs[speed]));
}
}
}
@@ -1514,14 +1483,8 @@ public class StatsPullAtomService extends SystemService {
int pullCpuTimePerUidLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> {
long userTimeUs = timesUs[0], systemTimeUs = timesUs[1];
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeLong(userTimeUs)
- .writeLong(systemTimeUs)
- .build();
- pulledData.add(e);
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(atomTag, uid, userTimeUs, systemTimeUs));
});
return StatsManager.PULL_SUCCESS;
}
@@ -1545,14 +1508,8 @@ public class StatsPullAtomService extends SystemService {
mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
if (cpuFreqTimeMs[freqIndex] != 0) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeInt(freqIndex)
- .writeLong(cpuFreqTimeMs[freqIndex])
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, uid, freqIndex, cpuFreqTimeMs[freqIndex]));
}
}
});
@@ -1576,13 +1533,7 @@ public class StatsPullAtomService extends SystemService {
int pullCpuActiveTimeLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeLong(cpuActiveTimesMs)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, uid, cpuActiveTimesMs));
});
return StatsManager.PULL_SUCCESS;
}
@@ -1605,14 +1556,8 @@ public class StatsPullAtomService extends SystemService {
int pullCpuClusterTimeLocked(int atomTag, List<StatsEvent> pulledData) {
mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> {
for (int i = 0; i < cpuClusterTimesMs.length; i++) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeInt(i)
- .writeLong(cpuClusterTimesMs[i])
- .build();
- pulledData.add(e);
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(atomTag, uid, i, cpuClusterTimesMs[i]));
}
});
return StatsManager.PULL_SUCCESS;
@@ -1651,16 +1596,12 @@ public class StatsPullAtomService extends SystemService {
if (wifiInfo == null) {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(wifiInfo.getTimeSinceBootMillis())
- .writeInt(wifiInfo.getStackState())
- .writeLong(wifiInfo.getControllerTxDurationMillis())
- .writeLong(wifiInfo.getControllerRxDurationMillis())
- .writeLong(wifiInfo.getControllerIdleDurationMillis())
- .writeLong(wifiInfo.getControllerEnergyUsedMicroJoules())
- .build();
- pulledData.add(e);
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(atomTag, wifiInfo.getTimeSinceBootMillis(),
+ wifiInfo.getStackState(), wifiInfo.getControllerTxDurationMillis(),
+ wifiInfo.getControllerRxDurationMillis(),
+ wifiInfo.getControllerIdleDurationMillis(),
+ wifiInfo.getControllerEnergyUsedMicroJoules()));
} catch (RuntimeException e) {
Slog.e(TAG, "failed to getWifiActivityEnergyInfoAsync", e);
return StatsManager.PULL_SKIP;
@@ -1689,19 +1630,15 @@ public class StatsPullAtomService extends SystemService {
if (modemInfo == null) {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(modemInfo.getTimestamp())
- .writeLong(modemInfo.getSleepTimeMillis())
- .writeLong(modemInfo.getIdleTimeMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis())
- .writeLong(modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis())
- .writeLong(modemInfo.getReceiveTimeMillis())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, modemInfo.getTimestamp(),
+ modemInfo.getSleepTimeMillis(), modemInfo.getIdleTimeMillis(),
+ modemInfo.getTransmitPowerInfo().get(0).getTimeInMillis(),
+ modemInfo.getTransmitPowerInfo().get(1).getTimeInMillis(),
+ modemInfo.getTransmitPowerInfo().get(2).getTimeInMillis(),
+ modemInfo.getTransmitPowerInfo().get(3).getTimeInMillis(),
+ modemInfo.getTransmitPowerInfo().get(4).getTimeInMillis(),
+ modemInfo.getReceiveTimeMillis(),
+ -1 /*`energy_used` field name deprecated, use -1 to indicate as unused.*/));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1723,16 +1660,10 @@ public class StatsPullAtomService extends SystemService {
if (info == null) {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(info.getTimeStamp())
- .writeInt(info.getBluetoothStackState())
- .writeLong(info.getControllerTxTimeMillis())
- .writeLong(info.getControllerRxTimeMillis())
- .writeLong(info.getControllerIdleTimeMillis())
- .writeLong(info.getControllerEnergyUsed())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, info.getTimeStamp(),
+ info.getBluetoothStackState(), info.getControllerTxTimeMillis(),
+ info.getControllerRxTimeMillis(), info.getControllerIdleTimeMillis(),
+ info.getControllerEnergyUsed()));
return StatsManager.PULL_SUCCESS;
}
@@ -1751,11 +1682,7 @@ public class StatsPullAtomService extends SystemService {
}
int pullSystemElapsedRealtimeLocked(int atomTag, List<StatsEvent> pulledData) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(SystemClock.elapsedRealtime())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, SystemClock.elapsedRealtime()));
return StatsManager.PULL_SUCCESS;
}
@@ -1770,11 +1697,7 @@ public class StatsPullAtomService extends SystemService {
}
int pullSystemUptimeLocked(int atomTag, List<StatsEvent> pulledData) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(SystemClock.uptimeMillis())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, SystemClock.uptimeMillis()));
return StatsManager.PULL_SUCCESS;
}
@@ -1801,22 +1724,10 @@ public class StatsPullAtomService extends SystemService {
if (memoryStat == null) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(processMemoryState.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(processMemoryState.processName)
- .writeInt(processMemoryState.oomScore)
- .writeLong(memoryStat.pgfault)
- .writeLong(memoryStat.pgmajfault)
- .writeLong(memoryStat.rssInBytes)
- .writeLong(memoryStat.cacheInBytes)
- .writeLong(memoryStat.swapInBytes)
- .writeLong(-1) // unused
- .writeLong(-1) // unused
- .writeInt(-1) // unused
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, processMemoryState.uid,
+ processMemoryState.processName, processMemoryState.oomScore, memoryStat.pgfault,
+ memoryStat.pgmajfault, memoryStat.rssInBytes, memoryStat.cacheInBytes,
+ memoryStat.swapInBytes, -1 /*unused*/, -1 /*unused*/, -1 /*unused*/));
}
return StatsManager.PULL_SUCCESS;
}
@@ -1840,16 +1751,11 @@ public class StatsPullAtomService extends SystemService {
if (snapshot == null) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(managedProcess.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(managedProcess.processName)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, managedProcess.uid,
+ managedProcess.processName,
// RSS high-water mark in bytes.
- .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
- .writeInt(snapshot.rssHighWaterMarkInKilobytes)
- .build();
- pulledData.add(e);
+ snapshot.rssHighWaterMarkInKilobytes * 1024L,
+ snapshot.rssHighWaterMarkInKilobytes));
}
// Complement the data with native system processes
SparseArray<String> processCmdlines = getProcessCmdlines();
@@ -1860,16 +1766,11 @@ public class StatsPullAtomService extends SystemService {
if (snapshot == null) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(snapshot.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(processCmdlines.valueAt(i))
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, snapshot.uid,
+ processCmdlines.valueAt(i),
// RSS high-water mark in bytes.
- .writeLong(snapshot.rssHighWaterMarkInKilobytes * 1024L)
- .writeInt(snapshot.rssHighWaterMarkInKilobytes)
- .build();
- pulledData.add(e);
+ snapshot.rssHighWaterMarkInKilobytes * 1024L,
+ snapshot.rssHighWaterMarkInKilobytes));
}
// Invoke rss_hwm_reset binary to reset RSS HWM counters for all processes.
SystemProperties.set("sys.rss_hwm_reset.on", "1");
@@ -1895,19 +1796,10 @@ public class StatsPullAtomService extends SystemService {
if (snapshot == null) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(managedProcess.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(managedProcess.processName)
- .writeInt(managedProcess.pid)
- .writeInt(managedProcess.oomScore)
- .writeInt(snapshot.rssInKilobytes)
- .writeInt(snapshot.anonRssInKilobytes)
- .writeInt(snapshot.swapInKilobytes)
- .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, managedProcess.uid,
+ managedProcess.processName, managedProcess.pid, managedProcess.oomScore,
+ snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes,
+ snapshot.anonRssInKilobytes + snapshot.swapInKilobytes));
}
// Complement the data with native system processes. Given these measurements can be taken
// in response to LMKs happening, we want to first collect the managed app stats (to
@@ -1921,19 +1813,11 @@ public class StatsPullAtomService extends SystemService {
if (snapshot == null) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(snapshot.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(processCmdlines.valueAt(i))
- .writeInt(pid)
- .writeInt(-1001) // Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.
- .writeInt(snapshot.rssInKilobytes)
- .writeInt(snapshot.anonRssInKilobytes)
- .writeInt(snapshot.swapInKilobytes)
- .writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, snapshot.uid,
+ processCmdlines.valueAt(i), pid,
+ -1001 /*Placeholder for native processes, OOM_SCORE_ADJ_MIN - 1.*/,
+ snapshot.rssInKilobytes, snapshot.anonRssInKilobytes, snapshot.swapInKilobytes,
+ snapshot.anonRssInKilobytes + snapshot.swapInKilobytes));
}
return StatsManager.PULL_SUCCESS;
}
@@ -1950,11 +1834,7 @@ public class StatsPullAtomService extends SystemService {
int pullSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs();
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(systemIonHeapSizeInBytes)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, systemIonHeapSizeInBytes));
return StatsManager.PULL_SUCCESS;
}
@@ -1973,11 +1853,7 @@ public class StatsPullAtomService extends SystemService {
int pullIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb();
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(ionHeapSizeInKilobytes)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, ionHeapSizeInKilobytes));
return StatsManager.PULL_SUCCESS;
}
@@ -1994,16 +1870,10 @@ public class StatsPullAtomService extends SystemService {
int pullProcessSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) {
List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs();
for (IonAllocations allocations : result) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(getUidForPid(allocations.pid))
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(readCmdlineFromProcfs(allocations.pid))
- .writeInt((int) (allocations.totalSizeInBytes / 1024))
- .writeInt(allocations.count)
- .writeInt((int) (allocations.maxSizeInBytes / 1024))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, getUidForPid(allocations.pid),
+ readCmdlineFromProcfs(allocations.pid),
+ (int) (allocations.totalSizeInBytes / 1024), allocations.count,
+ (int) (allocations.maxSizeInBytes / 1024)));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2027,14 +1897,8 @@ public class StatsPullAtomService extends SystemService {
try {
Temperature temperatures[] = thermalService.getCurrentTemperatures();
for (Temperature temp : temperatures) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(temp.getType())
- .writeString(temp.getName())
- .writeInt((int) (temp.getValue() * 10))
- .writeInt(temp.getStatus())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, temp.getType(),
+ temp.getName(), (int) (temp.getValue() * 10), temp.getStatus()));
}
} catch (RemoteException e) {
// Should not happen.
@@ -2065,13 +1929,8 @@ public class StatsPullAtomService extends SystemService {
try {
CoolingDevice devices[] = thermalService.getCurrentCoolingDevices();
for (CoolingDevice device : devices) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(device.getType())
- .writeString(device.getName())
- .writeInt((int) (device.getValue()))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, device.getType(), device.getName(), (int) (device.getValue())));
}
} catch (RemoteException e) {
// Should not happen.
@@ -2107,25 +1966,12 @@ public class StatsPullAtomService extends SystemService {
List<ExportedCallStat> callStats = binderStats.getExportedCallStats();
binderStats.reset();
for (ExportedCallStat callStat : callStats) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(callStat.workSourceUid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(callStat.className)
- .writeString(callStat.methodName)
- .writeLong(callStat.callCount)
- .writeLong(callStat.exceptionCount)
- .writeLong(callStat.latencyMicros)
- .writeLong(callStat.maxLatencyMicros)
- .writeLong(callStat.cpuTimeMicros)
- .writeLong(callStat.maxCpuTimeMicros)
- .writeLong(callStat.maxReplySizeBytes)
- .writeLong(callStat.maxRequestSizeBytes)
- .writeLong(callStat.recordedCallCount)
- .writeInt(callStat.screenInteractive ? 1 : 0)
- .writeInt(callStat.callingUid)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, callStat.workSourceUid,
+ callStat.className, callStat.methodName, callStat.callCount,
+ callStat.exceptionCount, callStat.latencyMicros, callStat.maxLatencyMicros,
+ callStat.cpuTimeMicros, callStat.maxCpuTimeMicros, callStat.maxReplySizeBytes,
+ callStat.maxRequestSizeBytes, callStat.recordedCallCount,
+ callStat.screenInteractive, callStat.callingUid));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2152,12 +1998,8 @@ public class StatsPullAtomService extends SystemService {
// TODO: decouple binder calls exceptions with the rest of the binder calls data so that we
// can reset the exception stats.
for (Map.Entry<String, Integer> entry : exceptionStats.entrySet()) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeString(entry.getKey())
- .writeInt(entry.getValue())
- .build();
- pulledData.add(e);
+ pulledData.add(
+ FrameworkStatsLog.buildStatsEvent(atomTag, entry.getKey(), entry.getValue()));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2184,26 +2026,12 @@ public class StatsPullAtomService extends SystemService {
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
looperStats.reset();
for (LooperStats.ExportedEntry entry : entries) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(entry.workSourceUid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(entry.handlerClassName)
- .writeString(entry.threadName)
- .writeString(entry.messageName)
- .writeLong(entry.messageCount)
- .writeLong(entry.exceptionCount)
- .writeLong(entry.recordedMessageCount)
- .writeLong(entry.totalLatencyMicros)
- .writeLong(entry.cpuUsageMicros)
- .writeBoolean(entry.isInteractive)
- .writeLong(entry.maxCpuUsageMicros)
- .writeLong(entry.maxLatencyMicros)
- .writeLong(entry.recordedDelayMessageCount)
- .writeLong(entry.delayMillis)
- .writeLong(entry.maxDelayMillis)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, entry.workSourceUid,
+ entry.handlerClassName, entry.threadName, entry.messageName, entry.messageCount,
+ entry.exceptionCount, entry.recordedMessageCount, entry.totalLatencyMicros,
+ entry.cpuUsageMicros, entry.isInteractive, entry.maxCpuUsageMicros,
+ entry.maxLatencyMicros, entry.recordedDelayMessageCount, entry.delayMillis,
+ entry.maxDelayMillis));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2264,13 +2092,7 @@ public class StatsPullAtomService extends SystemService {
}
// Add info pulledData.
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(latency)
- .writeBoolean(fileBased)
- .writeInt(writeSpeed)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, latency, fileBased, writeSpeed));
return StatsManager.PULL_SUCCESS;
}
@@ -2289,29 +2111,17 @@ public class StatsPullAtomService extends SystemService {
StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath());
StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath());
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__DATA)
- .writeLong(statFsData.getAvailableBytes())
- .writeLong(statFsData.getTotalBytes())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__DATA, statFsData.getAvailableBytes(),
+ statFsData.getTotalBytes()));
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE)
- .writeLong(statFsCache.getAvailableBytes())
- .writeLong(statFsCache.getTotalBytes())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE,
+ statFsCache.getAvailableBytes(), statFsCache.getTotalBytes()));
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM)
- .writeLong(statFsSystem.getAvailableBytes())
- .writeLong(statFsSystem.getTotalBytes())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM,
+ statFsSystem.getAvailableBytes(), statFsSystem.getTotalBytes()));
return StatsManager.PULL_SUCCESS;
}
@@ -2342,15 +2152,10 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
for (int i = 0; i < length; i++) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeString(pkg_names.getString(i))
- .writeLong(app_sizes.optLong(i, /* fallback */ -1L))
- .writeLong(app_data_sizes.optLong(i, /* fallback */ -1L))
- .writeLong(app_cache_sizes.optLong(i, /* fallback */ -1L))
- .writeLong(cache_time)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pkg_names.getString(i),
+ app_sizes.optLong(i, /* fallback */ -1L),
+ app_data_sizes.optLong(i, /* fallback */ -1L),
+ app_cache_sizes.optLong(i, /* fallback */ -1L), cache_time));
}
} catch (IOException | JSONException e) {
Slog.w(TAG, "Unable to read diskstats cache file within pullAppSize");
@@ -2376,86 +2181,45 @@ public class StatsPullAtomService extends SystemService {
long cacheTime = json.optLong(
DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, /* fallback */ -1L);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE)
- .writeLong(json.optLong(
- DiskStatsFileLogger.APP_SIZE_AGG_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE)
- .writeLong(json.optLong(
- DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE)
- .writeLong(json.optLong(
- DiskStatsFileLogger.APP_CACHE_AGG_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS)
- .writeLong(json.optLong(
- DiskStatsFileLogger.PHOTOS_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS)
- .writeLong(
- json.optLong(DiskStatsFileLogger.VIDEOS_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__AUDIO)
- .writeLong(json.optLong(
- DiskStatsFileLogger.AUDIO_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS)
- .writeLong(
- json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM)
- .writeLong(json.optLong(
- DiskStatsFileLogger.SYSTEM_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
-
- e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__OTHER)
- .writeLong(json.optLong(
- DiskStatsFileLogger.MISC_KEY, /* fallback */ -1L))
- .writeLong(cacheTime)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE,
+ json.optLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY, /* fallback */ -1L),
+ cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE,
+ json.optLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, /* fallback */ -1L),
+ cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE,
+ json.optLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY, /* fallback */ -1L),
+ cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS,
+ json.optLong(DiskStatsFileLogger.PHOTOS_KEY, /* fallback */ -1L), cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS,
+ json.optLong(DiskStatsFileLogger.VIDEOS_KEY, /* fallback */ -1L), cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__AUDIO,
+ json.optLong(DiskStatsFileLogger.AUDIO_KEY, /* fallback */ -1L), cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS,
+ json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, /* fallback */ -1L),
+ cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM,
+ json.optLong(DiskStatsFileLogger.SYSTEM_KEY, /* fallback */ -1L), cacheTime));
+
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ FrameworkStatsLog.CATEGORY_SIZE__CATEGORY__OTHER,
+ json.optLong(DiskStatsFileLogger.MISC_KEY, /* fallback */ -1L), cacheTime));
} catch (IOException | JSONException e) {
Slog.w(TAG, "Unable to read diskstats cache file within pullCategorySize");
return StatsManager.PULL_SKIP;
@@ -2519,12 +2283,7 @@ public class StatsPullAtomService extends SystemService {
} else {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(userId)
- .writeInt(numEnrolled)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, userId, numEnrolled));
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -2578,16 +2337,12 @@ public class StatsPullAtomService extends SystemService {
for (int i = 0; i < protoStreams.length; i++) {
byte[] bytes = protoStreams[i].getBytes(); // cache the value
if (bytes.length > 0) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeByteArray(bytes)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, bytes,
// This is a shard ID, and is specified in the metric definition to be
// a dimension. This will result in statsd using RANDOM_ONE_SAMPLE to
// keep all the shards, as it thinks each shard is a different dimension
// of data.
- .writeInt(i)
- .build();
- pulledData.add(e);
+ i));
}
}
@@ -2640,26 +2395,13 @@ public class StatsPullAtomService extends SystemService {
}
int pullDiskIOLocked(int atomTag, List<StatsEvent> pulledData) {
- mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead,
- fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite,
- fgFsync, bgFsync) -> {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeLong(fgCharsRead)
- .writeLong(fgCharsWrite)
- .writeLong(fgBytesRead)
- .writeLong(fgBytesWrite)
- .writeLong(bgCharsRead)
- .writeLong(bgCharsWrite)
- .writeLong(bgBytesRead)
- .writeLong(bgBytesWrite)
- .writeLong(fgFsync)
- .writeLong(bgFsync)
- .build();
- pulledData.add(e);
- });
+ mStoragedUidIoStatsReader.readAbsolute(
+ (uid, fgCharsRead, fgCharsWrite, fgBytesRead, fgBytesWrite, bgCharsRead,
+ bgCharsWrite, bgBytesRead, bgBytesWrite, fgFsync, bgFsync) -> {
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, uid, fgCharsRead,
+ fgCharsWrite, fgBytesRead, fgBytesWrite, bgCharsRead, bgCharsWrite,
+ bgBytesRead, bgBytesWrite, fgFsync, bgFsync));
+ });
return StatsManager.PULL_SUCCESS;
}
@@ -2678,11 +2420,7 @@ public class StatsPullAtomService extends SystemService {
ProtoOutputStream proto = new ProtoOutputStream();
powerProfile.dumpDebug(proto);
proto.flush();
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeByteArray(proto.getBytes())
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, proto.getBytes()));
return StatsManager.PULL_SUCCESS;
}
@@ -2708,15 +2446,8 @@ public class StatsPullAtomService extends SystemService {
mProcessCpuTracker.update();
for (int i = 0; i < mProcessCpuTracker.countStats(); i++) {
ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(st.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(st.name)
- .writeLong(st.base_utime)
- .writeLong(st.base_stime)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, st.uid, st.name, st.base_utime, st.base_stime));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2766,27 +2497,27 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeInt(processCpuUsage.uid);
- e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
- e.writeInt(processCpuUsage.processId);
- e.writeInt(threadCpuUsage.threadId);
- e.writeString(processCpuUsage.processName);
- e.writeString(threadCpuUsage.threadName);
+ int[] frequencies = new int[CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES];
+ int[] usageTimesMillis = new int[CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES];
for (int k = 0; k < CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES; k++) {
if (k < cpuFrequencies.length) {
- e.writeInt(cpuFrequencies[k]);
- e.writeInt(threadCpuUsage.usageTimesMillis[k]);
+ frequencies[k] = cpuFrequencies[k];
+ usageTimesMillis[k] = threadCpuUsage.usageTimesMillis[k];
} else {
// If we have no more frequencies to write, we still must write empty data.
// We know that this data is empty (and not just zero) because all
// frequencies are expected to be greater than zero
- e.writeInt(0);
- e.writeInt(0);
+ frequencies[k] = 0;
+ usageTimesMillis[k] = 0;
}
}
- pulledData.add(e.build());
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, processCpuUsage.uid,
+ processCpuUsage.processId, threadCpuUsage.threadId,
+ processCpuUsage.processName, threadCpuUsage.threadName, frequencies[0],
+ usageTimesMillis[0], frequencies[1], usageTimesMillis[1], frequencies[2],
+ usageTimesMillis[2], frequencies[3], usageTimesMillis[3], frequencies[4],
+ usageTimesMillis[4], frequencies[5], usageTimesMillis[5], frequencies[6],
+ usageTimesMillis[6], frequencies[7], usageTimesMillis[7]));
}
}
return StatsManager.PULL_SUCCESS;
@@ -2834,11 +2565,8 @@ public class StatsPullAtomService extends SystemService {
int pullDeviceCalculatedPowerUseLocked(int atomTag, List<StatsEvent> pulledData) {
BatteryStatsHelper bsHelper = getBatteryStatsHelper();
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower()))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, milliAmpHrsToNanoAmpSecs(bsHelper.getComputedPower())));
return StatsManager.PULL_SUCCESS;
}
@@ -2862,13 +2590,8 @@ public class StatsPullAtomService extends SystemService {
if (bs.drainType != bs.drainType.APP) {
continue;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(bs.uidObj.getUid())
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, bs.uidObj.getUid(), milliAmpHrsToNanoAmpSecs(bs.totalPowerMah)));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2896,12 +2619,8 @@ public class StatsPullAtomService extends SystemService {
if (bs.drainType == bs.drainType.USER) {
continue; // This is not supported. We purposefully calculate over USER_ALL.
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(bs.drainType.ordinal())
- .writeLong(milliAmpHrsToNanoAmpSecs(bs.totalPowerMah))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, bs.drainType.ordinal(), milliAmpHrsToNanoAmpSecs(bs.totalPowerMah)));
}
return StatsManager.PULL_SUCCESS;
}
@@ -2924,28 +2643,16 @@ public class StatsPullAtomService extends SystemService {
final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0
? 0 : elapsedMillis - mDebugElapsedClockPreviousValue;
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mDebugElapsedClockPullCount)
- .writeLong(elapsedMillis)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, mDebugElapsedClockPullCount,
+ elapsedMillis,
// Log it twice to be able to test multi-value aggregation from ValueMetric.
- .writeLong(elapsedMillis)
- .writeLong(clockDiffMillis)
- .writeInt(1 /* always set */)
- .build();
- pulledData.add(e);
+ elapsedMillis, clockDiffMillis, 1 /* always set */));
if (mDebugElapsedClockPullCount % 2 == 1) {
- StatsEvent e2 = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mDebugElapsedClockPullCount)
- .writeLong(elapsedMillis)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, mDebugElapsedClockPullCount,
+ elapsedMillis,
// Log it twice to be able to test multi-value aggregation from ValueMetric.
- .writeLong(elapsedMillis)
- .writeLong(clockDiffMillis)
- .writeInt(2 /* set on odd pulls */)
- .build();
- pulledData.add(e2);
+ elapsedMillis, clockDiffMillis, 2 /* set on odd pulls */));
}
mDebugElapsedClockPullCount++;
@@ -2975,16 +2682,13 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeLong(mDebugFailingElapsedClockPullCount)
- .writeLong(elapsedMillis)
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ mDebugFailingElapsedClockPullCount, elapsedMillis,
// Log it twice to be able to test multi-value aggregation from ValueMetric.
- .writeLong(elapsedMillis)
- .writeLong(mDebugFailingElapsedClockPreviousValue == 0
- ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue)
- .build();
- pulledData.add(e);
+ elapsedMillis,
+ mDebugFailingElapsedClockPreviousValue == 0
+ ? 0
+ : elapsedMillis - mDebugFailingElapsedClockPreviousValue));
mDebugFailingElapsedClockPreviousValue = elapsedMillis;
return StatsManager.PULL_SUCCESS;
@@ -3001,19 +2705,9 @@ public class StatsPullAtomService extends SystemService {
}
int pullBuildInformationLocked(int atomTag, List<StatsEvent> pulledData) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeString(Build.FINGERPRINT)
- .writeString(Build.BRAND)
- .writeString(Build.PRODUCT)
- .writeString(Build.DEVICE)
- .writeString(Build.VERSION.RELEASE_OR_CODENAME)
- .writeString(Build.ID)
- .writeString(Build.VERSION.INCREMENTAL)
- .writeString(Build.TYPE)
- .writeString(Build.TAGS)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, Build.FINGERPRINT, Build.BRAND,
+ Build.PRODUCT, Build.DEVICE, Build.VERSION.RELEASE_OR_CODENAME, Build.ID,
+ Build.VERSION.INCREMENTAL, Build.TYPE, Build.TAGS));
return StatsManager.PULL_SUCCESS;
}
@@ -3059,14 +2753,8 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(pkg.applicationInfo.uid)
- .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true)
- .writeString(holderName)
- .writeString(roleName)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, pkg.applicationInfo.uid, holderName, roleName));
}
}
}
@@ -3144,19 +2832,24 @@ public class StatsPullAtomService extends SystemService {
permName = permName.substring(COMMON_PERMISSION_PREFIX.length());
}
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeString(permName);
- e.writeInt(pkg.applicationInfo.uid);
- e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
+ StatsEvent e;
if (atomTag == FrameworkStatsLog.DANGEROUS_PERMISSION_STATE) {
- e.writeString("");
+ e = FrameworkStatsLog.buildStatsEvent(atomTag, permName,
+ pkg.applicationInfo.uid, "",
+ (pkg.requestedPermissionsFlags[permNum]
+ & REQUESTED_PERMISSION_GRANTED)
+ != 0,
+ permissionFlags);
+ } else {
+ // DangerousPermissionStateSampled atom.
+ e = FrameworkStatsLog.buildStatsEvent(atomTag, permName,
+ pkg.applicationInfo.uid,
+ (pkg.requestedPermissionsFlags[permNum]
+ & REQUESTED_PERMISSION_GRANTED)
+ != 0,
+ permissionFlags);
}
- e.writeBoolean((pkg.requestedPermissionsFlags[permNum]
- & REQUESTED_PERMISSION_GRANTED) != 0);
- e.writeInt(permissionFlags);
-
- pulledData.add(e.build());
+ pulledData.add(e);
}
}
}
@@ -3188,11 +2881,7 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SKIP;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeString(tzDbVersion)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, tzDbVersion));
return StatsManager.PULL_SUCCESS;
}
@@ -3234,13 +2923,8 @@ public class StatsPullAtomService extends SystemService {
externalStorageType = StorageEnums.OTHER;
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(externalStorageType)
- .writeInt(volumeType)
- .writeLong(diskInfo.size)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, externalStorageType, volumeType, diskInfo.size));
}
}
return StatsManager.PULL_SUCCESS;
@@ -3291,12 +2975,8 @@ public class StatsPullAtomService extends SystemService {
// App is installed on external storage.
if (externalStorageType != -1) {
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(externalStorageType)
- .writeString(appInfo.packageName)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(
+ atomTag, externalStorageType, appInfo.packageName));
}
}
return StatsManager.PULL_SUCCESS;
@@ -3339,16 +3019,10 @@ public class StatsPullAtomService extends SystemService {
mContext.getContentResolver(),
Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeBoolean(unlockKeyguardEnabled != 0)
- .writeBoolean(unlockDismissesKeyguard != 0)
- .writeBoolean(unlockAttentionRequired != 0)
- .writeBoolean(unlockAppEnabled != 0)
- .writeBoolean(unlockAlwaysRequireConfirmation != 0)
- .writeBoolean(unlockDiversityRequired != 0)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
+ unlockKeyguardEnabled != 0, unlockDismissesKeyguard != 0,
+ unlockAttentionRequired != 0, unlockAppEnabled != 0,
+ unlockAlwaysRequireConfirmation != 0, unlockDiversityRequired != 0));
}
} finally {
Binder.restoreCallingIdentity(callingToken);
@@ -3429,27 +3103,29 @@ public class StatsPullAtomService extends SystemService {
if (entry.mHash >= samplingRate) {
continue;
}
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeInt(entry.mUid);
- e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
- e.writeString(entry.mPackageName);
+ StatsEvent e;
if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
- e.writeString(entry.mAttributionTag);
- }
- e.writeInt(entry.mOp.getOpCode());
- e.writeLong(entry.mOp.getForegroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(entry.mOp.getBackgroundAccessCount(OP_FLAGS_PULLED));
- e.writeLong(entry.mOp.getForegroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(entry.mOp.getBackgroundRejectCount(OP_FLAGS_PULLED));
- e.writeLong(entry.mOp.getForegroundAccessDuration(OP_FLAGS_PULLED));
- e.writeLong(entry.mOp.getBackgroundAccessDuration(OP_FLAGS_PULLED));
- e.writeBoolean(mDangerousAppOpsList.contains(entry.mOp.getOpCode()));
-
- if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
- e.writeInt(samplingRate);
+ e = FrameworkStatsLog.buildStatsEvent(atomTag, entry.mUid, entry.mPackageName,
+ entry.mAttributionTag, entry.mOp.getOpCode(),
+ entry.mOp.getForegroundAccessCount(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundAccessCount(OP_FLAGS_PULLED),
+ entry.mOp.getForegroundRejectCount(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundRejectCount(OP_FLAGS_PULLED),
+ entry.mOp.getForegroundAccessDuration(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundAccessDuration(OP_FLAGS_PULLED),
+ mDangerousAppOpsList.contains(entry.mOp.getOpCode()), samplingRate);
+ } else {
+ // AppOps atom.
+ e = FrameworkStatsLog.buildStatsEvent(atomTag, entry.mUid, entry.mPackageName,
+ entry.mOp.getOpCode(), entry.mOp.getForegroundAccessCount(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundAccessCount(OP_FLAGS_PULLED),
+ entry.mOp.getForegroundRejectCount(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundRejectCount(OP_FLAGS_PULLED),
+ entry.mOp.getForegroundAccessDuration(OP_FLAGS_PULLED),
+ entry.mOp.getBackgroundAccessDuration(OP_FLAGS_PULLED),
+ mDangerousAppOpsList.contains(entry.mOp.getOpCode()));
}
- pulledData.add(e.build());
+ pulledData.add(e);
}
if (pulledData.size() > DIMENSION_KEY_SIZE_HARD_LIMIT) {
int adjustedSamplingRate = constrain(
@@ -3610,22 +3286,11 @@ public class StatsPullAtomService extends SystemService {
return StatsManager.PULL_SUCCESS;
}
- StatsEvent.Builder e = StatsEvent.newBuilder();
- e.setAtomId(atomTag);
- e.writeInt(message.getUid());
- e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
- e.writeString(message.getPackageName());
- e.writeString("");
- if (message.getAttributionTag() == null) {
- e.writeString("");
- } else {
- e.writeString(message.getAttributionTag());
- }
- e.writeString(message.getMessage());
- e.writeInt(message.getSamplingStrategy());
- e.writeInt(AppOpsManager.strOpToOp(message.getOp()));
-
- pulledData.add(e.build());
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, message.getUid(),
+ message.getPackageName(), "",
+ message.getAttributionTag() == null ? "" : message.getAttributionTag(),
+ message.getMessage(), message.getSamplingStrategy(),
+ AppOpsManager.strOpToOp(message.getOp())));
} catch (Throwable t) {
// TODO: catch exceptions at a more granular level
Slog.e(TAG, "Could not read runtime appop access message", t);
@@ -3641,11 +3306,7 @@ public class StatsPullAtomService extends SystemService {
InputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(statsFiles.get(0));
int[] len = new int[1];
byte[] stats = readFully(stream, len);
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeByteArray(Arrays.copyOf(stats, len[0]))
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, Arrays.copyOf(stats, len[0])));
}
static byte[] readFully(InputStream stream, int[] outLen) throws IOException {
@@ -3808,11 +3469,7 @@ public class StatsPullAtomService extends SystemService {
throw new IllegalStateException("Invalid atomTag in healthHal puller: "
+ atomTag);
}
- StatsEvent e = StatsEvent.newBuilder()
- .setAtomId(atomTag)
- .writeInt(pulledValue)
- .build();
- pulledData.add(e);
+ pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag, pulledValue));
});
} catch (RemoteException | IllegalStateException e) {
return StatsManager.PULL_SKIP;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 4e355f0dadfc..bec0ce944e3f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7465,7 +7465,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
* {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
- * should be visible depending on Keyguard state
+ * should be visible depending on Keyguard and window state.
*
* @return true if the screen can be turned on, false otherwise.
*/
@@ -7474,8 +7474,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
final ActivityStack stack = getRootTask();
- return stack != null &&
- stack.checkKeyguardVisibility(this, true /* shouldBeVisible */,
+ return stack != null
+ && !stack.inMultiWindowMode()
+ && stack.checkKeyguardVisibility(this, true /* shouldBeVisible */,
stack.topRunningActivity() == this /* isTop */);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1d1c31b8226c..8fff81a1e8c4 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3459,9 +3459,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
InsetsControlTarget getImeFallback() {
// host is in non-default display that doesn't support system decor, default to
// default display's StatusBar to control IME (when available), else let system control it.
- WindowState statusBar =
- mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar();
- return statusBar != null ? statusBar : mRemoteInsetsControlTarget;
+ final DisplayContent defaultDc = mWmService.getDefaultDisplayContentLocked();
+ WindowState statusBar = defaultDc.getDisplayPolicy().getStatusBar();
+ return statusBar != null ? statusBar : defaultDc.mRemoteInsetsControlTarget;
}
boolean canShowIme() {
@@ -3521,7 +3521,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
@VisibleForTesting
InsetsControlTarget computeImeControlTarget() {
- if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
+ if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null
+ || (mInputMethodInputTarget != null
+ && getImeHostOrFallback(mInputMethodInputTarget.getWindow())
+ == mRemoteInsetsControlTarget)) {
return mRemoteInsetsControlTarget;
} else {
// Now, a special case -- if the last target's window is in the process of exiting, but
@@ -4039,36 +4042,16 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return null;
}
- int dw = mDisplayInfo.logicalWidth;
- int dh = mDisplayInfo.logicalHeight;
-
- if (dw <= 0 || dh <= 0) {
- return null;
- }
-
- final Rect frame = new Rect(0, 0, dw, dh);
-
- // The screenshot API does not apply the current screen rotation.
- int rot = mDisplay.getRotation();
-
- if (rot == ROTATION_90 || rot == ROTATION_270) {
- rot = (rot == ROTATION_90) ? ROTATION_270 : ROTATION_90;
- }
-
- // SurfaceFlinger is not aware of orientation, so convert our logical
- // crop to SurfaceFlinger's portrait orientation.
- convertCropForSurfaceFlinger(frame, rot, dw, dh);
-
final ScreenRotationAnimation screenRotationAnimation =
mWmService.mRoot.getDisplayContent(DEFAULT_DISPLAY).getRotationAnimation();
final boolean inRotation = screenRotationAnimation != null &&
screenRotationAnimation.isAnimating();
if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM, "Taking screenshot while rotating");
- // TODO(b/68392460): We should screenshot Task controls directly
- // but it's difficult at the moment as the Task doesn't have the
- // correct size set.
- final Bitmap bitmap = SurfaceControl.screenshot(frame, dw, dh, inRotation, rot);
+ // Send invalid rect and no width and height since it will screenshot the entire display.
+ Rect frame = new Rect(0, 0, -1, -1);
+ final Bitmap bitmap = SurfaceControl.screenshot(frame, 0, 0, inRotation,
+ mDisplay.getRotation());
if (bitmap == null) {
Slog.w(TAG_WM, "Failed to take screenshot");
return null;
@@ -4083,30 +4066,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return ret;
}
- // TODO: Can this use createRotationMatrix()?
- private static void convertCropForSurfaceFlinger(Rect crop, int rot, int dw, int dh) {
- if (rot == Surface.ROTATION_90) {
- final int tmp = crop.top;
- crop.top = dw - crop.right;
- crop.right = crop.bottom;
- crop.bottom = dw - crop.left;
- crop.left = tmp;
- } else if (rot == Surface.ROTATION_180) {
- int tmp = crop.top;
- crop.top = dh - crop.bottom;
- crop.bottom = dh - tmp;
- tmp = crop.right;
- crop.right = dw - crop.left;
- crop.left = dw - tmp;
- } else if (rot == Surface.ROTATION_270) {
- final int tmp = crop.top;
- crop.top = crop.left;
- crop.left = dh - crop.bottom;
- crop.bottom = crop.right;
- crop.right = dh - tmp;
- }
- }
-
void setExitingTokensHasVisible(boolean hasVisible) {
for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
mExitingTokens.get(i).hasVisible = hasVisible;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index b4ead8eccf02..82277511ef79 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -102,6 +102,11 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_UNKNOWN;
import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
@@ -314,6 +319,17 @@ public class DisplayPolicy {
private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+ // Alternative status bar for when flexible insets mapping is used to place the status bar on
+ // another side of the screen.
+ private WindowState mStatusBarAlt = null;
+ @WindowManagerPolicy.AltBarPosition
+ private int mStatusBarAltPosition = ALT_BAR_UNKNOWN;
+ // Alternative navigation bar for when flexible insets mapping is used to place the navigation
+ // bar elsewhere on the screen.
+ private WindowState mNavigationBarAlt = null;
+ @WindowManagerPolicy.AltBarPosition
+ private int mNavigationBarAltPosition = ALT_BAR_UNKNOWN;
+
/** See {@link #getNavigationBarFrameHeight} */
private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
@@ -373,7 +389,10 @@ public class DisplayPolicy {
private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
private static final Rect sTmpRect = new Rect();
private static final Rect sTmpNavFrame = new Rect();
+ private static final Rect sTmpStatusFrame = new Rect();
+ private static final Rect sTmpScreenDecorFrame = new Rect();
private static final Rect sTmpLastParentFrame = new Rect();
+ private static final Rect sTmpDisplayFrameBounds = new Rect();
private WindowState mTopFullscreenOpaqueWindowState;
private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
@@ -431,7 +450,7 @@ public class DisplayPolicy {
case MSG_REQUEST_TRANSIENT_BARS:
synchronized (mLock) {
WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
- ? mStatusBar : mNavigationBar;
+ ? getStatusBar() : getNavigationBar();
if (targetBar != null) {
requestTransientBars(targetBar);
}
@@ -494,6 +513,7 @@ public class DisplayPolicy {
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
}
}
@@ -504,6 +524,7 @@ public class DisplayPolicy {
&& mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
}
}
@@ -520,6 +541,7 @@ public class DisplayPolicy {
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
}
excludedRegion.recycle();
}
@@ -537,6 +559,7 @@ public class DisplayPolicy {
excludedRegion)) {
requestTransientBars(mNavigationBar);
}
+ checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
}
excludedRegion.recycle();
}
@@ -638,6 +661,15 @@ public class DisplayPolicy {
mHandler.post(mGestureNavigationSettingsObserver::register);
}
+ private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
+ if (mStatusBarAlt != null && mStatusBarAltPosition == pos) {
+ requestTransientBars(mStatusBarAlt);
+ }
+ if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) {
+ requestTransientBars(mNavigationBarAlt);
+ }
+ }
+
void systemReady() {
mSystemGestures.systemReady();
if (mService.mPointerLocationEnabled) {
@@ -899,6 +931,14 @@ public class DisplayPolicy {
}
break;
}
+
+ // Check if alternate bars positions were updated.
+ if (mStatusBarAlt == win) {
+ mStatusBarAltPosition = getAltBarPosition(attrs);
+ }
+ if (mNavigationBarAlt == win) {
+ mNavigationBarAltPosition = getAltBarPosition(attrs);
+ }
}
/**
@@ -943,10 +983,9 @@ public class DisplayPolicy {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
- if (mStatusBar != null) {
- if (mStatusBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
+ if ((mStatusBar != null && mStatusBar.isAlive())
+ || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
break;
case TYPE_NOTIFICATION_SHADE:
@@ -963,10 +1002,9 @@ public class DisplayPolicy {
mContext.enforcePermission(
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
- if (mNavigationBar != null) {
- if (mNavigationBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
+ if ((mNavigationBar != null && mNavigationBar.isAlive())
+ || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
}
break;
case TYPE_NAVIGATION_BAR_PANEL:
@@ -993,10 +1031,43 @@ public class DisplayPolicy {
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
+
+ for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) {
+ switch (insetType) {
+ case ITYPE_STATUS_BAR:
+ if ((mStatusBar != null && mStatusBar.isAlive())
+ || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ break;
+ case ITYPE_NAVIGATION_BAR:
+ if ((mNavigationBar != null && mNavigationBar.isAlive())
+ || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ break;
+ }
+ }
}
return ADD_OKAY;
}
+ private void getRotatedWindowBounds(DisplayFrames displayFrames, WindowState windowState,
+ Rect outBounds) {
+ outBounds.set(windowState.getBounds());
+
+ int windowRotation = windowState.getWindowConfiguration().getRotation();
+ if (windowRotation == displayFrames.mRotation) {
+ return;
+ }
+
+ // Get displayFrames bounds
+ sTmpDisplayFrameBounds.set(0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
+ // Rotate the WindowState's bounds based on the displayFrames rotation
+ mDisplayContent.rotateBounds(sTmpDisplayFrameBounds, windowRotation,
+ displayFrames.mRotation, outBounds);
+ }
+
/**
* Called when a window is being added to the system. Must not throw an exception.
*
@@ -1020,7 +1091,6 @@ public class DisplayPolicy {
mStatusBarController.setWindow(win);
final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
(displayFrames, windowState, rect) -> {
- rect.set(windowState.getFrameLw());
rect.bottom = rect.top + getStatusBarHeight(displayFrames);
};
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
@@ -1041,7 +1111,7 @@ public class DisplayPolicy {
displayFrames.mDisplayHeight,
displayFrames.mRotation) == NAV_BAR_BOTTOM
&& !mNavButtonForcedVisible) {
- sTmpRect.set(windowState.getFrameLw());
+ sTmpRect.set(inOutFrame);
sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
inOutFrame.top = sTmpRect.bottom
- getNavigationBarHeight(displayFrames.mRotation,
@@ -1083,7 +1153,19 @@ public class DisplayPolicy {
break;
default:
if (attrs.providesInsetsTypes != null) {
- for (int insetsType : attrs.providesInsetsTypes) {
+ for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
+ switch (insetsType) {
+ case ITYPE_STATUS_BAR:
+ mStatusBarAlt = win;
+ mStatusBarController.setWindow(mStatusBarAlt);
+ mStatusBarAltPosition = getAltBarPosition(attrs);
+ break;
+ case ITYPE_NAVIGATION_BAR:
+ mNavigationBarAlt = win;
+ mNavigationBarController.setWindow(mNavigationBarAlt);
+ mNavigationBarAltPosition = getAltBarPosition(attrs);
+ break;
+ }
mDisplayContent.setInsetProvider(insetsType, win, null);
}
}
@@ -1091,6 +1173,22 @@ public class DisplayPolicy {
}
}
+ @WindowManagerPolicy.AltBarPosition
+ private int getAltBarPosition(WindowManager.LayoutParams params) {
+ switch (params.gravity) {
+ case Gravity.LEFT:
+ return ALT_BAR_LEFT;
+ case Gravity.RIGHT:
+ return ALT_BAR_RIGHT;
+ case Gravity.BOTTOM:
+ return ALT_BAR_BOTTOM;
+ case Gravity.TOP:
+ return ALT_BAR_TOP;
+ default:
+ return ALT_BAR_UNKNOWN;
+ }
+ }
+
TriConsumer<DisplayFrames, WindowState, Rect> getImeSourceFrameProvider() {
return (displayFrames, windowState, inOutFrame) -> {
if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth,
@@ -1131,12 +1229,14 @@ public class DisplayPolicy {
* @param win The window being removed.
*/
void removeWindowLw(WindowState win) {
- if (mStatusBar == win) {
+ if (mStatusBar == win || mStatusBarAlt == win) {
mStatusBar = null;
+ mStatusBarAlt = null;
mStatusBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
- } else if (mNavigationBar == win) {
+ } else if (mNavigationBar == win || mNavigationBarAlt == win) {
mNavigationBar = null;
+ mNavigationBarAlt = null;
mNavigationBarController.setWindow(null);
mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
} else if (mNotificationShade == win) {
@@ -1162,7 +1262,7 @@ public class DisplayPolicy {
}
WindowState getStatusBar() {
- return mStatusBar;
+ return mStatusBar != null ? mStatusBar : mStatusBarAlt;
}
WindowState getNotificationShade() {
@@ -1170,7 +1270,7 @@ public class DisplayPolicy {
}
WindowState getNavigationBar() {
- return mNavigationBar;
+ return mNavigationBar != null ? mNavigationBar : mNavigationBarAlt;
}
/**
@@ -1232,6 +1332,46 @@ public class DisplayPolicy {
return R.anim.dock_left_enter;
}
}
+ } else if (win == mStatusBarAlt || win == mNavigationBarAlt) {
+ if (win.getAttrs().windowAnimations != 0) {
+ return ANIMATION_STYLEABLE;
+ }
+
+ int pos = (win == mStatusBarAlt) ? mStatusBarAltPosition : mNavigationBarAltPosition;
+
+ boolean isExitOrHide = transit == TRANSIT_EXIT || transit == TRANSIT_HIDE;
+ boolean isEnterOrShow = transit == TRANSIT_ENTER || transit == TRANSIT_SHOW;
+
+ switch (pos) {
+ case ALT_BAR_LEFT:
+ if (isExitOrHide) {
+ return R.anim.dock_left_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_left_enter;
+ }
+ break;
+ case ALT_BAR_RIGHT:
+ if (isExitOrHide) {
+ return R.anim.dock_right_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_right_enter;
+ }
+ break;
+ case ALT_BAR_BOTTOM:
+ if (isExitOrHide) {
+ return R.anim.dock_bottom_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_bottom_enter;
+ }
+ break;
+ case ALT_BAR_TOP:
+ if (isExitOrHide) {
+ return R.anim.dock_top_exit;
+ } else if (isEnterOrShow) {
+ return R.anim.dock_top_enter;
+ }
+ break;
+ }
}
if (transit == TRANSIT_PREVIEW_DONE) {
@@ -1590,7 +1730,7 @@ public class DisplayPolicy {
mInputConsumer = null;
Slog.v(TAG, INPUT_CONSUMER_NAVIGATION + " dismissed.");
}
- } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
+ } else if (mInputConsumer == null && getStatusBar() != null && canHideNavigationBar()) {
mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
mHandler.getLooper(),
INPUT_CONSUMER_NAVIGATION,
@@ -1669,11 +1809,13 @@ public class DisplayPolicy {
if (isSimulatedLayout) {
w.setSimulatedWindowFrames(simulatedFrames);
}
- Rect bounds = w.getBounds();
+ getRotatedWindowBounds(displayFrames, w, sTmpScreenDecorFrame);
final WindowFrames windowFrames = w.getLayoutingWindowFrames();
- windowFrames.setFrames(bounds /* parentFrame */, bounds /* displayFrame */,
- bounds /* contentFrame */, bounds /* visibleFrame */, sTmpRect /* decorFrame */,
- bounds /* stableFrame */);
+ windowFrames.setFrames(sTmpScreenDecorFrame /* parentFrame */,
+ sTmpScreenDecorFrame /* displayFrame */,
+ sTmpScreenDecorFrame /* contentFrame */,
+ sTmpScreenDecorFrame /* visibleFrame */, sTmpRect /* decorFrame */,
+ sTmpScreenDecorFrame /* stableFrame */);
try {
w.computeFrame(displayFrames);
} finally {
@@ -1731,12 +1873,13 @@ public class DisplayPolicy {
return false;
}
// apply any status bar insets
- Rect bounds = mStatusBar.getBounds();
+ getRotatedWindowBounds(displayFrames, mStatusBar, sTmpStatusFrame);
sTmpRect.setEmpty();
final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames();
- windowFrames.setFrames(bounds /* parentFrame */, bounds /* displayFrame */,
- bounds /* contentFrame */, bounds /* visibleFrame */, sTmpRect /* decorFrame */,
- bounds /* stableFrame */);
+ windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
+ sTmpStatusFrame /* displayFrame */, sTmpStatusFrame /* contentFrame */,
+ sTmpStatusFrame /* visibleFrame */, sTmpRect /* decorFrame */,
+ sTmpStatusFrame /* stableFrame */);
// Let the status bar determine its size.
mStatusBar.computeFrame(displayFrames);
@@ -1807,7 +1950,7 @@ public class DisplayPolicy {
final Rect dockFrame = displayFrames.mDock;
final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
- navigationFrame.set(mNavigationBar.getBounds());
+ getRotatedWindowBounds(displayFrames, mNavigationBar, navigationFrame);
final Rect cutoutSafeUnrestricted = sTmpRect;
cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
@@ -2047,7 +2190,8 @@ public class DisplayPolicy {
final @InsetsType int typesToFit = attrs.getFitInsetsTypes();
final @InsetsSide int sidesToFit = attrs.getFitInsetsSides();
final ArraySet<Integer> types = InsetsState.toInternalType(typesToFit);
- final Rect dfu = win.getBounds();
+ getRotatedWindowBounds(displayFrames, win, sTmpRect);
+ final Rect dfu = sTmpRect;
Insets insets = Insets.of(0, 0, 0, 0);
for (int i = types.size() - 1; i >= 0; i--) {
final InsetsSource source = mDisplayContent.getInsetsPolicy()
@@ -2062,7 +2206,7 @@ public class DisplayPolicy {
final int top = (sidesToFit & Side.TOP) != 0 ? insets.top : 0;
final int right = (sidesToFit & Side.RIGHT) != 0 ? insets.right : 0;
final int bottom = (sidesToFit & Side.BOTTOM) != 0 ? insets.bottom : 0;
- df.set(left, top, dfu.right - right, dfu.bottom - bottom);
+ df.set(dfu.left + left, dfu.top + top, dfu.right - right, dfu.bottom - bottom);
if (attached == null) {
pf.set(df);
vf.set(adjust != SOFT_INPUT_ADJUST_NOTHING
@@ -2676,10 +2820,10 @@ public class DisplayPolicy {
mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
}
- if (mStatusBar != null) {
+ if (getStatusBar() != null) {
if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
+ " top=" + mTopFullscreenOpaqueWindowState);
- final boolean forceShowStatusBar = (mStatusBar.getAttrs().privateFlags
+ final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
& PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
final boolean notificationShadeForcesShowingNavigation =
mNotificationShade != null
@@ -3165,6 +3309,16 @@ public class DisplayPolicy {
return mNavigationBarPosition;
}
+ @WindowManagerPolicy.AltBarPosition
+ int getAlternateStatusBarPosition() {
+ return mStatusBarAltPosition;
+ }
+
+ @WindowManagerPolicy.AltBarPosition
+ int getAlternateNavBarPosition() {
+ return mNavigationBarAltPosition;
+ }
+
/**
* A new window has been focused.
*/
@@ -3326,8 +3480,8 @@ public class DisplayPolicy {
final boolean isFullscreen = (visibility & (View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) != 0
|| (PolicyControl.getWindowFlags(win, win.mAttrs) & FLAG_FULLSCREEN) != 0
- || (mStatusBar != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
- || (mNavigationBar != null && insetsPolicy.isHidden(
+ || (getStatusBar() != null && insetsPolicy.isHidden(ITYPE_STATUS_BAR))
+ || (getNavigationBar() != null && insetsPolicy.isHidden(
ITYPE_NAVIGATION_BAR));
final int behavior = win.mAttrs.insetsFlags.behavior;
final boolean isImmersive = (visibility & (View.SYSTEM_UI_FLAG_IMMERSIVE
@@ -3582,7 +3736,7 @@ public class DisplayPolicy {
final boolean hideNavBarSysui =
(vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
- final boolean transientStatusBarAllowed = mStatusBar != null
+ final boolean transientStatusBarAllowed = getStatusBar() != null
&& (notificationShadeHasFocus || (!mForceShowSystemBars
&& (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
@@ -3740,7 +3894,7 @@ public class DisplayPolicy {
// TODO(b/118118435): Remove this after migration
private boolean isImmersiveMode(int vis) {
final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return mNavigationBar != null
+ return getNavigationBar() != null
&& (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
&& (vis & flags) != 0
&& canHideNavigationBar();
@@ -3748,7 +3902,7 @@ public class DisplayPolicy {
private boolean isImmersiveMode(WindowState win) {
final int behavior = win.mAttrs.insetsFlags.behavior;
- return mNavigationBar != null
+ return getNavigationBar() != null
&& canHideNavigationBar()
&& (behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE
|| behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE)
@@ -3829,8 +3983,8 @@ public class DisplayPolicy {
public void takeScreenshot(int screenshotType, int source) {
if (mScreenshotHelper != null) {
mScreenshotHelper.takeScreenshot(screenshotType,
- mStatusBar != null && mStatusBar.isVisibleLw(),
- mNavigationBar != null && mNavigationBar.isVisibleLw(),
+ getStatusBar() != null && getStatusBar().isVisibleLw(),
+ getNavigationBar() != null && getNavigationBar().isVisibleLw(),
source, mHandler, null /* completionConsumer */);
}
}
@@ -3868,6 +4022,11 @@ public class DisplayPolicy {
if (mStatusBar != null) {
pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
}
+ if (mStatusBarAlt != null) {
+ pw.print(prefix); pw.print("mStatusBarAlt="); pw.print(mStatusBarAlt);
+ pw.print(prefix); pw.print("mStatusBarAltPosition=");
+ pw.println(mStatusBarAltPosition);
+ }
if (mNotificationShade != null) {
pw.print(prefix); pw.print("mExpandedPanel="); pw.print(mNotificationShade);
}
@@ -3879,6 +4038,11 @@ public class DisplayPolicy {
pw.print(prefix); pw.print("mNavigationBarPosition=");
pw.println(mNavigationBarPosition);
}
+ if (mNavigationBarAlt != null) {
+ pw.print(prefix); pw.print("mNavigationBarAlt="); pw.println(mNavigationBarAlt);
+ pw.print(prefix); pw.print("mNavigationBarAltPosition=");
+ pw.println(mNavigationBarAltPosition);
+ }
if (mFocusedWindow != null) {
pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 99ee5e121b7a..e7fbc334306e 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -32,7 +32,7 @@ import java.io.PrintWriter;
*/
class ImeInsetsSourceProvider extends InsetsSourceProvider {
- private WindowState mImeTargetFromIme;
+ private InsetsControlTarget mImeTargetFromIme;
private Runnable mShowImeRunner;
private boolean mIsImeLayoutDrawn;
@@ -47,10 +47,12 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
*
* @param imeTarget imeTarget on which IME request is coming from.
*/
- void scheduleShowImePostLayout(WindowState imeTarget) {
+ void scheduleShowImePostLayout(InsetsControlTarget imeTarget) {
boolean targetChanged = mImeTargetFromIme != imeTarget
&& mImeTargetFromIme != null && imeTarget != null && mShowImeRunner != null
- && mImeTargetFromIme.mActivityRecord == imeTarget.mActivityRecord;
+ && imeTarget.getWindow() != null && mImeTargetFromIme.getWindow() != null
+ && mImeTargetFromIme.getWindow().mActivityRecord
+ == imeTarget.getWindow().mActivityRecord;
mImeTargetFromIme = imeTarget;
if (targetChanged) {
// target changed, check if new target can show IME.
@@ -62,7 +64,8 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
return;
}
- ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeTargetFromIme.getName());
+ ProtoLog.d(WM_DEBUG_IME, "Schedule IME show for %s", mImeTargetFromIme.getWindow() == null
+ ? mImeTargetFromIme : mImeTargetFromIme.getWindow().getName());
mShowImeRunner = () -> {
ProtoLog.d(WM_DEBUG_IME, "Run showImeRunner");
// Target should still be the same.
@@ -127,13 +130,17 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
return false;
}
ProtoLog.d(WM_DEBUG_IME, "dcTarget: %s mImeTargetFromIme: %s",
- dcTarget.getName(), mImeTargetFromIme.getName());
+ dcTarget.getName(), mImeTargetFromIme.getWindow() == null
+ ? mImeTargetFromIme : mImeTargetFromIme.getWindow().getName());
return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget)
- || (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
- && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
+ || (mImeTargetFromIme != null && mImeTargetFromIme.getWindow() != null
+ && dcTarget.getParentWindow() == mImeTargetFromIme
+ && dcTarget.mSubLayer > mImeTargetFromIme.getWindow().mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
- || (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
+ || controlTarget == mImeTargetFromIme
+ && (mImeTargetFromIme.getWindow() == null
+ || !mImeTargetFromIme.getWindow().isClosing());
}
@Override
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ab2151974ce9..f3e23169fee0 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2269,6 +2269,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent display = getChildAt(displayNdx);
+ if (display.shouldSleep()) {
+ continue;
+ }
+
final boolean curResult = result;
boolean resumedOnDisplay = display.reduceOnAllTaskDisplayAreas(
(taskDisplayArea, resumed) -> {
@@ -2360,7 +2364,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// process the keyguard going away, which can happen before the sleep
// token is released. As a result, it is important we resume the
// activity here.
- resumeFocusedStacksTopActivities();
+ stack.resumeTopActivityUncheckedLocked(null, null);
}
// The visibility update must not be called before resuming the top, so the
// display orientation can be updated first if needed. Otherwise there may
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index f13dfdd1156f..68445f6970fb 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -615,8 +615,9 @@ class TaskSnapshotController {
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
return state.calculateInsets(frame, null /* ignoringVisibilityState */,
false /* isScreenRound */, false /* alwaysConsumeSystemBars */,
- null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacySystemUiFlags */,
- null /* typeSideMap */).getInsets(WindowInsets.Type.systemBars()).toRect();
+ null /* displayCutout */, 0 /* legacySoftInputMode */, 0 /* legacyWindowFlags */,
+ 0 /* legacySystemUiFlags */, null /* typeSideMap */).getInsets(
+ WindowInsets.Type.systemBars()).toRect();
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 85972bffd755..aa691fc1ae6b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2165,6 +2165,10 @@ public class WindowManagerService extends IWindowManager.Stub
throw new IllegalArgumentException(
"Window type can not be changed after the window is added.");
}
+ if (!Arrays.equals(win.mAttrs.providesInsetsTypes, attrs.providesInsetsTypes)) {
+ throw new IllegalArgumentException(
+ "Insets types can not be changed after the window is added.");
+ }
// Odd choice but less odd than embedding in copyFrom()
if ((attrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY)
@@ -7599,13 +7603,14 @@ public class WindowManagerService extends IWindowManager.Stub
if (imeTarget == null) {
return;
}
- imeTarget = imeTarget.getImeControlTarget().getWindow();
+ final InsetsControlTarget controlTarget = imeTarget.getImeControlTarget();
+ imeTarget = controlTarget.getWindow();
// If InsetsControlTarget doesn't have a window, its using remoteControlTarget which
// is controlled by default display
final DisplayContent dc = imeTarget != null
? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked();
dc.getInsetsStateController().getImeSourceProvider()
- .scheduleShowImePostLayout(imeTarget);
+ .scheduleShowImePostLayout(controlTarget);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 27c4bf42ac1b..7afed3ccc6ca 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2191,6 +2191,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isInputMethodTarget()) {
dc.computeImeTarget(true /* updateImeTarget */);
}
+ if (dc.mInputMethodInputTarget == this) {
+ dc.setInputMethodInputTarget(null);
+ }
if (dc.mInputMethodControlTarget == this) {
dc.updateImeControlTarget();
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 3450c3ae9fb3..a5f0d045948c 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1422,6 +1422,11 @@ static long elapsedMcs(Duration start, Duration end) {
}
// Extract lib files from zip, create new files in incfs and write data to them
+// Lib files should be placed next to the APK file in the following matter:
+// Example:
+// /path/to/base.apk
+// /path/to/lib/arm/first.so
+// /path/to/lib/arm/second.so
bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath,
std::string_view abi, bool extractNativeLibs) {
@@ -1433,9 +1438,13 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
return false;
}
+ const auto targetLibPathRelativeToStorage =
+ path::join(path::dirname(normalizePathToStorage(*ifs, storage, apkFullPath)),
+ libDirRelativePath);
+
// First prepare target directories if they don't exist yet
- if (auto res = makeDirs(*ifs, storage, libDirRelativePath, 0755)) {
- LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
+ if (auto res = makeDirs(*ifs, storage, targetLibPathRelativeToStorage, 0755)) {
+ LOG(ERROR) << "Failed to prepare target lib directory " << targetLibPathRelativeToStorage
<< " errno: " << res;
return false;
}
@@ -1486,7 +1495,7 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
auto startFileTs = Clock::now();
const auto libName = path::basename(fileName);
- auto targetLibPath = path::join(libDirRelativePath, libName);
+ auto targetLibPath = path::join(targetLibPathRelativeToStorage, libName);
const auto targetLibPathAbsolute = normalizePathToStorage(*ifs, storage, targetLibPath);
// If the extract file already exists, skip
if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) {
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index dfe75ed50cd4..06d51a4be920 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -61,7 +61,7 @@ import com.android.server.backup.testing.BackupManagerServiceTestUtils;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.transport.TransportNotRegisteredException;
-import com.android.server.testing.shadows.ShadowAppBackupUtils;
+import com.android.server.testing.shadows.ShadowBackupEligibilityRules;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
@@ -99,7 +99,7 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(
shadows = {
- ShadowAppBackupUtils.class,
+ ShadowBackupEligibilityRules.class,
ShadowApplicationPackageManager.class,
ShadowSystemServiceRegistry.class
})
@@ -159,7 +159,7 @@ public class UserBackupManagerServiceTest {
@After
public void tearDown() throws Exception {
mBackupThread.quit();
- ShadowAppBackupUtils.reset();
+ ShadowBackupEligibilityRules.reset();
ShadowApplicationPackageManager.reset();
}
@@ -236,7 +236,7 @@ public class UserBackupManagerServiceTest {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
registerPackages(PACKAGE_1);
- ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
+ ShadowBackupEligibilityRules.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1);
@@ -255,7 +255,7 @@ public class UserBackupManagerServiceTest {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
registerPackages(PACKAGE_1);
- ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
+ ShadowBackupEligibilityRules.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
@@ -273,7 +273,7 @@ public class UserBackupManagerServiceTest {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
registerPackages(PACKAGE_1, PACKAGE_2);
- ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
+ ShadowBackupEligibilityRules.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String[] filtered =
@@ -801,7 +801,7 @@ public class UserBackupManagerServiceTest {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
for (String packageName : packages) {
registerPackages(packageName);
- ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(packageName);
+ ShadowBackupEligibilityRules.setAppRunningAndEligibleForBackupWithTransport(packageName);
}
setUpCurrentTransport(mTransportManager, mTransport);
}
@@ -962,7 +962,7 @@ public class UserBackupManagerServiceTest {
@Config(shadows = ShadowKeyValueBackupTask.class)
public void testRequestBackup_whenPackageIsFullBackup() throws Exception {
setUpForRequestBackup(PACKAGE_1);
- ShadowAppBackupUtils.setAppGetsFullBackup(PACKAGE_1);
+ ShadowBackupEligibilityRules.setAppGetsFullBackup(PACKAGE_1);
UserBackupManagerService backupManagerService =
createBackupManagerServiceForRequestBackup();
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index b5c9375fcc0d..6184c4ed7f1a 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -115,6 +115,7 @@ import com.android.server.backup.testing.TestUtils.ThrowingRunnable;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
+import com.android.server.backup.utils.BackupEligibilityRules;
import com.android.server.testing.shadows.FrameworkShadowLooper;
import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBackupDataInput;
@@ -176,6 +177,7 @@ public class KeyValueBackupTaskTest {
private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
"android.app.backup.BackupAgent$SharedPrefsSynchronizer";
private static final int USER_ID = 10;
+ private static final int OPERATION_TYPE = BackupManager.OperationType.BACKUP;
@Mock private TransportManager mTransportManager;
@Mock private DataChangedJournal mOldJournal;
@@ -183,6 +185,7 @@ public class KeyValueBackupTaskTest {
@Mock private IBackupManagerMonitor mMonitor;
@Mock private OnTaskFinishedListener mListener;
@Mock private PackageManagerInternal mPackageManagerInternal;
+
private UserBackupManagerService mBackupManagerService;
private TransportData mTransport;
private ShadowLooper mShadowBackupLooper;
@@ -198,6 +201,7 @@ public class KeyValueBackupTaskTest {
private Looper mMainLooper;
private FrameworkShadowLooper mShadowMainLooper;
private Context mContext;
+ private BackupEligibilityRules mBackupEligibilityRules;
@Before
public void setUp() throws Exception {
@@ -253,6 +257,8 @@ public class KeyValueBackupTaskTest {
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
+ mBackupEligibilityRules = new BackupEligibilityRules(mPackageManager,
+ LocalServices.getService(PackageManagerInternal.class), USER_ID, OPERATION_TYPE);
}
@After
@@ -479,7 +485,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
runTask(task);
@@ -492,7 +499,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task =
createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE);
@@ -506,7 +514,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgentWithData(PACKAGE_1);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
runTask(task);
@@ -742,7 +751,7 @@ public class KeyValueBackupTaskTest {
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
- verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ verify(mObserver).backupFinished(SUCCESS);
assertBackupPendingFor(PACKAGE_1);
}
@@ -775,7 +784,7 @@ public class KeyValueBackupTaskTest {
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
- verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ verify(mObserver).backupFinished(SUCCESS);
assertBackupPendingFor(PACKAGE_1);
}
@@ -792,7 +801,7 @@ public class KeyValueBackupTaskTest {
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
- verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ verify(mObserver).backupFinished(SUCCESS);
assertBackupPendingFor(PACKAGE_1);
}
@@ -810,7 +819,7 @@ public class KeyValueBackupTaskTest {
verify(mBackupManagerService).setWorkSource(null);
verify(mObserver).onResult(PACKAGE_1.packageName, ERROR_AGENT_FAILURE);
- verify(mObserver).backupFinished(BackupManager.SUCCESS);
+ verify(mObserver).backupFinished(SUCCESS);
assertBackupPendingFor(PACKAGE_1);
}
@@ -1316,7 +1325,8 @@ public class KeyValueBackupTaskTest {
argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
.then(copyBackupDataTo(backupDataPath));
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
agentOnBackupDo(
pmAgent,
(oldState, dataOutput, newState) -> {
@@ -1380,7 +1390,8 @@ public class KeyValueBackupTaskTest {
setUpAgent(PACKAGE_1);
when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
agentOnBackupDo(
pmAgent,
(oldState, dataOutput, newState) -> {
@@ -1404,7 +1415,8 @@ public class KeyValueBackupTaskTest {
setUpAgent(PACKAGE_1);
when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
agentOnBackupDo(
pmAgent,
(oldState, dataOutput, newState) -> {
@@ -1669,7 +1681,7 @@ public class KeyValueBackupTaskTest {
verify(mReporter).onPackageBackupTransportFailure(PACKAGE_1.packageName);
verify(mReporter).onTransportNotInitialized(mTransport.transportName);
- verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+ verify(mReporter).onBackupFinished(ERROR_TRANSPORT_ABORTED);
}
@Test
@@ -1686,7 +1698,7 @@ public class KeyValueBackupTaskTest {
verify(mReporter).onPackageBackupTransportFailure(PM_PACKAGE.packageName);
verify(mReporter).onTransportNotInitialized(mTransport.transportName);
- verify(mReporter).onBackupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+ verify(mReporter).onBackupFinished(ERROR_TRANSPORT_ABORTED);
}
@Test
@@ -1983,7 +1995,8 @@ public class KeyValueBackupTaskTest {
public void testRunTask_whenPmAgentFails_reportsCorrectly() throws Exception {
TransportMock transportMock = setUpInitializedTransport(mTransport);
BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
- when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+ when(mBackupManagerService.makeMetadataAgentWithEligibilityRules(
+ mBackupEligibilityRules)).thenReturn(pmAgent);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
runTask(task);
@@ -2001,7 +2014,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
- doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(pmAgent).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
runTask(task);
@@ -2014,7 +2028,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
- doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(pmAgent).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
runTask(task);
@@ -2027,7 +2042,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
- doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(pmAgent).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
runTask(task);
@@ -2040,7 +2056,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
agentOnBackupDo(
pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
@@ -2055,7 +2072,8 @@ public class KeyValueBackupTaskTest {
TransportMock transportMock = setUpInitializedTransport(mTransport);
setUpAgent(PACKAGE_1);
BackupAgent pmAgent = spy(createPmAgent());
- doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
+ doReturn(forward(pmAgent)).when(mBackupManagerService)
+ .makeMetadataAgentWithEligibilityRules(mBackupEligibilityRules);
KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
agentOnBackupDo(
pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
@@ -2652,14 +2670,16 @@ public class KeyValueBackupTaskTest {
mListener,
emptyList(),
/* userInitiated */ false,
- nonIncremental);
+ nonIncremental,
+ mBackupEligibilityRules);
mBackupManager.setUp(mBackupHandler, task);
return task;
}
private PackageManagerBackupAgent createPmAgent() {
PackageManagerBackupAgent pmAgent =
- new PackageManagerBackupAgent(mApplication.getPackageManager(), USER_ID);
+ new PackageManagerBackupAgent(mApplication.getPackageManager(), USER_ID,
+ mBackupEligibilityRules);
pmAgent.attach(mApplication);
pmAgent.onCreate();
return pmAgent;
@@ -2671,7 +2691,8 @@ public class KeyValueBackupTaskTest {
*/
private PackageManagerBackupAgent createThrowingPmAgent(RuntimeException exception) {
PackageManagerBackupAgent pmAgent =
- new ThrowingPackageManagerBackupAgent(mApplication.getPackageManager(), exception);
+ new ThrowingPackageManagerBackupAgent(mApplication.getPackageManager(), exception,
+ mBackupEligibilityRules);
pmAgent.attach(mApplication);
pmAgent.onCreate();
return pmAgent;
@@ -2985,8 +3006,9 @@ public class KeyValueBackupTaskTest {
private final RuntimeException mException;
ThrowingPackageManagerBackupAgent(
- PackageManager packageManager, RuntimeException exception) {
- super(packageManager, USER_ID);
+ PackageManager packageManager, RuntimeException exception,
+ BackupEligibilityRules backupEligibilityRules) {
+ super(packageManager, USER_ID, backupEligibilityRules);
mException = exception;
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupEligibilityRules.java
index aa1c6688b01d..566b0e151402 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupEligibilityRules.java
@@ -22,7 +22,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import com.android.server.backup.transport.TransportClient;
-import com.android.server.backup.utils.AppBackupUtils;
+import com.android.server.backup.utils.BackupEligibilityRules;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -31,8 +31,8 @@ import org.robolectric.annotation.Resetter;
import java.util.HashSet;
import java.util.Set;
-@Implements(AppBackupUtils.class)
-public class ShadowAppBackupUtils {
+@Implements(BackupEligibilityRules.class)
+public class ShadowBackupEligibilityRules {
private static final Set<String> sAppsRunningAndEligibleForBackupWithTransport =
new HashSet<>();
private static final Set<String> sAppsEligibleForBackup = new HashSet<>();
@@ -53,22 +53,19 @@ public class ShadowAppBackupUtils {
}
@Implementation
- protected static boolean appIsRunningAndEligibleForBackupWithTransport(
+ protected boolean appIsRunningAndEligibleForBackupWithTransport(
@Nullable TransportClient transportClient,
- String packageName,
- PackageManager pm,
- int userId) {
+ String packageName) {
return sAppsRunningAndEligibleForBackupWithTransport.contains(packageName);
}
@Implementation
- protected static boolean appIsEligibleForBackup(ApplicationInfo app, int userId,
- int operationType) {
+ protected boolean appIsEligibleForBackup(ApplicationInfo app) {
return sAppsEligibleForBackup.contains(app.packageName);
}
@Implementation
- protected static boolean appGetsFullBackup(PackageInfo packageInfo, int operationType) {
+ protected boolean appGetsFullBackup(PackageInfo packageInfo) {
return sAppsGetFullBackup.contains(packageInfo.packageName);
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java
index ac5d2da9c3cf..fd51df7ab1f9 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupTask.java
@@ -24,6 +24,7 @@ import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.keyvalue.KeyValueBackupReporter;
import com.android.server.backup.keyvalue.KeyValueBackupTask;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -63,7 +64,8 @@ public class ShadowKeyValueBackupTask {
OnTaskFinishedListener listener,
List<String> pendingFullBackups,
boolean userInitiated,
- boolean nonIncremental) {
+ boolean nonIncremental,
+ BackupEligibilityRules backupEligibilityRules) {
mListener = listener;
mQueue = queue;
mPendingFullBackups = pendingFullBackups;
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
index 8daef5fad032..5161070398d7 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
@@ -25,6 +25,7 @@ import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.restore.PerformUnifiedRestoreTask;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
@@ -67,7 +68,8 @@ public class ShadowPerformUnifiedRestoreTask {
int pmToken,
boolean isFullSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ BackupEligibilityRules backupEligibilityRules) {
mBackupManagerService = backupManagerService;
mPackage = targetPackage;
mIsFullSystemRestore = isFullSystemRestore;
diff --git a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index f0758dd3ef32..dcd7af31af93 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -57,6 +57,7 @@ import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
import android.provider.Settings.Global;
import android.test.mock.MockContentResolver;
import android.util.ArraySet;
@@ -94,6 +95,7 @@ import java.util.function.Consumer;
*
* Run with: atest com.android.server.AppStateTrackerTest
*/
+@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class AppStateTrackerTest {
@@ -130,6 +132,7 @@ public class AppStateTrackerTest {
@Override
AppStandbyInternal injectAppStandbyInternal() {
+ when(mMockAppStandbyInternal.isAppIdleEnabled()).thenReturn(true);
return mMockAppStandbyInternal;
}
@@ -141,7 +144,9 @@ public class AppStateTrackerTest {
}
@Override
- boolean isSmallBatteryDevice() { return mIsSmallBatteryDevice; };
+ boolean isSmallBatteryDevice() {
+ return mIsSmallBatteryDevice;
+ }
}
private static final int UID_1 = Process.FIRST_APPLICATION_UID + 1;
@@ -201,6 +206,13 @@ public class AppStateTrackerTest {
mMainHandler = new Handler(Looper.getMainLooper());
}
+ /**
+ * Enqueues a message and waits for it to complete. This ensures that any messages posted until
+ * now have been executed.
+ *
+ * Note that these messages may have enqueued more messages, which may or may not have executed
+ * when this method returns.
+ */
private void waitUntilMainHandlerDrain() throws Exception {
final CountDownLatch l = new CountDownLatch(1);
mMainHandler.post(() -> {
@@ -362,6 +374,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
areRestricted(instance, UID_1, PACKAGE_1, NONE);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -370,6 +383,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidGone(UID_1, /*disable=*/ false);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -378,12 +392,14 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
areRestricted(instance, UID_1, PACKAGE_1, NONE);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
mIUidObserver.onUidIdle(UID_1, /*disable=*/ false);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
areRestricted(instance, UID_1, PACKAGE_1, JOBS_AND_ALARMS);
areRestricted(instance, UID_2, PACKAGE_2, JOBS_AND_ALARMS);
areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
@@ -499,6 +515,8 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertTrue(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -517,6 +535,8 @@ public class AppStateTrackerTest {
ActivityManager.PROCESS_CAPABILITY_NONE);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertTrue(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -535,6 +555,8 @@ public class AppStateTrackerTest {
ActivityManager.PROCESS_CAPABILITY_NONE);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertTrue(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -546,6 +568,8 @@ public class AppStateTrackerTest {
mIUidObserver.onUidGone(UID_1, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertFalse(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -557,6 +581,8 @@ public class AppStateTrackerTest {
mIUidObserver.onUidIdle(UID_2, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertFalse(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -570,6 +596,8 @@ public class AppStateTrackerTest {
ActivityManager.PROCESS_CAPABILITY_NONE);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertFalse(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -583,6 +611,8 @@ public class AppStateTrackerTest {
ActivityManager.PROCESS_CAPABILITY_NONE);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
+
assertFalse(instance.isUidActive(UID_1));
assertFalse(instance.isUidActive(UID_2));
assertTrue(instance.isUidActive(Process.SYSTEM_UID));
@@ -1007,6 +1037,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1019,6 +1050,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidGone(UID_10_1, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1031,6 +1063,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1043,6 +1076,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidIdle(UID_10_1, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1069,6 +1103,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1081,6 +1116,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidGone(UID_10_1, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1093,6 +1129,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1105,6 +1142,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidIdle(UID_10_1, true);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
verify(l, times(0)).updateAllJobs();
verify(l, times(1)).updateJobsForUid(eq(UID_10_1), anyBoolean());
verify(l, times(0)).updateJobsForUidPackage(anyInt(), anyString(), anyBoolean());
@@ -1124,6 +1162,7 @@ public class AppStateTrackerTest {
mIUidObserver.onUidActive(UID_10_1);
waitUntilMainHandlerDrain();
+ waitUntilMainHandlerDrain();
setAppOps(UID_2, PACKAGE_2, true);
setAppOps(UID_10_2, PACKAGE_2, true);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
index c9e628480a52..70e6a340816a 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java
@@ -32,7 +32,10 @@ import static org.testng.Assert.assertTrue;
import static java.lang.Float.NaN;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.IBinder;
@@ -300,6 +303,26 @@ public class WindowMagnificationManagerTest {
assertFalse(mWindowMagnificationManager.isConnected());
}
+ @Test
+ public void requestConnection_registerAndUnregisterBroadcastReceiver() {
+ assertTrue(mWindowMagnificationManager.requestConnection(true));
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+
+ assertTrue(mWindowMagnificationManager.requestConnection(false));
+ verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
+ }
+
+ @Test
+ public void onReceiveScreenOff_removeMagnificationButtonAndDisableWindowMagnification()
+ throws RemoteException {
+ mWindowMagnificationManager.requestConnection(true);
+ mWindowMagnificationManager.mScreenStateReceiver.onReceive(mContext,
+ new Intent(Intent.ACTION_SCREEN_OFF));
+
+ verify(mMockConnection.getConnection()).removeMagnificationButton(TEST_DISPLAY);
+ verify(mMockConnection.getConnection()).disableWindowMagnification(TEST_DISPLAY);
+ }
+
private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
final int len = pointersLocation.length;
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index ccb2ea3e46da..b98f0257d7b7 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -18,6 +18,7 @@ package com.android.server.backup;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@@ -36,6 +37,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.params.BackupParams;
import com.android.server.backup.transport.TransportClient;
+import com.android.server.backup.utils.BackupEligibilityRules;
import org.junit.Before;
import org.junit.Test;
@@ -54,6 +56,7 @@ public class UserBackupManagerServiceTest {
@Mock IBackupObserver mBackupObserver;
@Mock PackageManager mPackageManager;
@Mock TransportClient mTransportClient;
+ @Mock BackupEligibilityRules mBackupEligibilityRules;
private TestBackupService mService;
@@ -82,54 +85,51 @@ public class UserBackupManagerServiceTest {
}
@Test
- public void getRequestBackupParams_isMigrationAndAppGetsFullBackup() throws Exception {
+ public void getRequestBackupParams_appIsEligibleForFullBackup() throws Exception {
when(mPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(
getPackageInfo(TEST_PACKAGE));
- mService.mAppIsEligibleForBackup = true;
- mService.mAppGetsFullBackup = true;
+ when(mBackupEligibilityRules.appIsEligibleForBackup(any())).thenReturn(true);
+ when(mBackupEligibilityRules.appGetsFullBackup(any())).thenReturn(true);
BackupParams params = mService.getRequestBackupParams(TEST_PACKAGES, mBackupObserver,
- mBackupManagerMonitor, /* flags */ 0, OperationType.MIGRATION,
+ mBackupManagerMonitor, /* flags */ 0, mBackupEligibilityRules,
mTransportClient, /* transportDirName */ "", OnTaskFinishedListener.NOP);
assertThat(params.kvPackages).isEmpty();
assertThat(params.fullPackages).contains(TEST_PACKAGE);
- assertThat(params.operationType).isEqualTo(OperationType.MIGRATION);
- assertThat(mService.mOperationType).isEqualTo(OperationType.MIGRATION);
+ assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
}
@Test
- public void getRequestBackupParams_isMigrationAndAppGetsKeyValueBackup() throws Exception {
+ public void getRequestBackupParams_appIsEligibleForKeyValueBackup() throws Exception {
when(mPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(
getPackageInfo(TEST_PACKAGE));
- mService.mAppIsEligibleForBackup = true;
- mService.mAppGetsFullBackup = false;
+ when(mBackupEligibilityRules.appIsEligibleForBackup(any())).thenReturn(true);
+ when(mBackupEligibilityRules.appGetsFullBackup(any())).thenReturn(false);
BackupParams params = mService.getRequestBackupParams(TEST_PACKAGES, mBackupObserver,
- mBackupManagerMonitor, /* flags */ 0, OperationType.MIGRATION,
+ mBackupManagerMonitor, /* flags */ 0, mBackupEligibilityRules,
mTransportClient, /* transportDirName */ "", OnTaskFinishedListener.NOP);
assertThat(params.kvPackages).contains(TEST_PACKAGE);
assertThat(params.fullPackages).isEmpty();
- assertThat(params.operationType).isEqualTo(OperationType.MIGRATION);
- assertThat(mService.mOperationType).isEqualTo(OperationType.MIGRATION);
+ assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
}
@Test
- public void getRequestBackupParams_isMigrationAndAppNotEligibleForBackup() throws Exception {
+ public void getRequestBackupParams_appIsNotEligibleForBackup() throws Exception {
when(mPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(
getPackageInfo(TEST_PACKAGE));
- mService.mAppIsEligibleForBackup = false;
- mService.mAppGetsFullBackup = false;
+ when(mBackupEligibilityRules.appIsEligibleForBackup(any())).thenReturn(false);
+ when(mBackupEligibilityRules.appGetsFullBackup(any())).thenReturn(false);
BackupParams params = mService.getRequestBackupParams(TEST_PACKAGES, mBackupObserver,
- mBackupManagerMonitor, /* flags */ 0, OperationType.MIGRATION,
+ mBackupManagerMonitor, /* flags */ 0, mBackupEligibilityRules,
mTransportClient, /* transportDirName */ "", OnTaskFinishedListener.NOP);
assertThat(params.kvPackages).isEmpty();
assertThat(params.fullPackages).isEmpty();
- assertThat(params.operationType).isEqualTo(OperationType.MIGRATION);
- assertThat(mService.mOperationType).isEqualTo(OperationType.MIGRATION);
+ assertThat(params.mBackupEligibilityRules).isEqualTo(mBackupEligibilityRules);
}
private static PackageInfo getPackageInfo(String packageName) {
@@ -141,9 +141,6 @@ public class UserBackupManagerServiceTest {
private static class TestBackupService extends UserBackupManagerService {
boolean isEnabledStatePersisted = false;
- boolean mAppIsEligibleForBackup = false;
- boolean mAppGetsFullBackup = false;
- int mOperationType = 0;
TestBackupService(Context context, PackageManager packageManager) {
super(context, packageManager);
@@ -161,18 +158,5 @@ public class UserBackupManagerServiceTest {
@Override
void updateStateOnBackupEnabled(boolean wasEnabled, boolean enable) {}
-
- @Override
- boolean appIsEligibleForBackup(ApplicationInfo applicationInfo, int userId,
- @OperationType int operationType) {
- mOperationType = operationType;
- return mAppIsEligibleForBackup;
- }
-
- @Override
- boolean appGetsFullBackup(PackageInfo packageInfo, @OperationType int operationType) {
- mOperationType = operationType;
- return mAppGetsFullBackup;
- }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 201211ef60bf..444155d12b3f 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -22,7 +22,6 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import android.app.backup.BackupManager;
import android.app.backup.BackupManager.OperationType;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -43,11 +42,13 @@ import com.android.server.backup.UserBackupManagerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class AppBackupUtilsTest {
+public class BackupEligibilityRulesTest {
private static final String CUSTOM_BACKUP_AGENT_NAME = "custom.backup.agent";
private static final String TEST_PACKAGE_NAME = "test_package";
@@ -56,15 +57,18 @@ public class AppBackupUtilsTest {
private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
- private PackageManagerInternal mMockPackageManagerInternal;
+ @Mock private PackageManagerInternal mMockPackageManagerInternal;
+ @Mock private PackageManager mPackageManager;
+ private BackupEligibilityRules mBackupEligibilityRules;
private int mUserId;
@Before
public void setUp() throws Exception {
- mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+ MockitoAnnotations.initMocks(this);
mUserId = UserHandle.USER_SYSTEM;
+ mBackupEligibilityRules = getBackupEligibilityRules(OperationType.BACKUP);
}
@Test
@@ -75,8 +79,7 @@ public class AppBackupUtilsTest {
applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
applicationInfo.packageName = TEST_PACKAGE_NAME;
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -90,8 +93,7 @@ public class AppBackupUtilsTest {
applicationInfo.backupAgentName = null;
applicationInfo.packageName = TEST_PACKAGE_NAME;
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -104,8 +106,7 @@ public class AppBackupUtilsTest {
applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -121,8 +122,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isTrue();
}
@@ -138,8 +138,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isTrue();
}
@@ -155,8 +154,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isTrue();
}
@@ -172,8 +170,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -189,8 +186,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -206,8 +202,7 @@ public class AppBackupUtilsTest {
when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.BACKUP);
+ boolean isEligible = mBackupEligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -218,8 +213,9 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
/* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.MIGRATION);
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+ OperationType.MIGRATION);
+ boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isTrue();
}
@@ -230,8 +226,9 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = getApplicationInfo(Process.SYSTEM_UID,
/* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
- boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
- mMockPackageManagerInternal, mUserId, OperationType.MIGRATION);
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+ OperationType.MIGRATION);
+ boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
assertThat(isEligible).isFalse();
}
@@ -248,7 +245,7 @@ public class AppBackupUtilsTest {
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isFalse();
}
@@ -266,7 +263,7 @@ public class AppBackupUtilsTest {
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isTrue();
}
@@ -283,7 +280,7 @@ public class AppBackupUtilsTest {
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isFalse();
}
@@ -300,7 +297,7 @@ public class AppBackupUtilsTest {
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isTrue();
}
@@ -316,7 +313,7 @@ public class AppBackupUtilsTest {
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isTrue();
}
@@ -332,7 +329,7 @@ public class AppBackupUtilsTest {
.thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
boolean isDisabled =
- AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
+ mBackupEligibilityRules.appIsDisabled(applicationInfo);
assertThat(isDisabled).isTrue();
}
@@ -342,7 +339,7 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
- boolean isStopped = AppBackupUtils.appIsStopped(applicationInfo);
+ boolean isStopped = mBackupEligibilityRules.appIsStopped(applicationInfo);
assertThat(isStopped).isTrue();
}
@@ -352,7 +349,7 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.flags = ~ApplicationInfo.FLAG_STOPPED;
- boolean isStopped = AppBackupUtils.appIsStopped(applicationInfo);
+ boolean isStopped = mBackupEligibilityRules.appIsStopped(applicationInfo);
assertThat(isStopped).isFalse();
}
@@ -363,7 +360,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.backupAgentName = null;
- boolean result = AppBackupUtils.appGetsFullBackup(packageInfo, OperationType.BACKUP);
+ boolean result = mBackupEligibilityRules.appGetsFullBackup(packageInfo);
assertThat(result).isTrue();
}
@@ -376,7 +373,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo.backupAgentName = "backup.agent";
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
- boolean result = AppBackupUtils.appGetsFullBackup(packageInfo, OperationType.BACKUP);
+ boolean result = mBackupEligibilityRules.appGetsFullBackup(packageInfo);
assertThat(result).isTrue();
}
@@ -389,7 +386,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo.backupAgentName = "backup.agent";
packageInfo.applicationInfo.flags = ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
- boolean result = AppBackupUtils.appGetsFullBackup(packageInfo, OperationType.BACKUP);
+ boolean result = mBackupEligibilityRules.appGetsFullBackup(packageInfo);
assertThat(result).isFalse();
}
@@ -401,7 +398,9 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
~ApplicationInfo.FLAG_FULL_BACKUP_ONLY, CUSTOM_BACKUP_AGENT_NAME);
- boolean result = AppBackupUtils.appGetsFullBackup(packageInfo, OperationType.MIGRATION);
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+ OperationType.MIGRATION);
+ boolean result = eligibilityRules.appGetsFullBackup(packageInfo);
assertThat(result).isTrue();
}
@@ -413,7 +412,9 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo = getApplicationInfo(Process.SYSTEM_UID,
~ApplicationInfo.FLAG_FULL_BACKUP_ONLY, CUSTOM_BACKUP_AGENT_NAME);
- boolean result = AppBackupUtils.appGetsFullBackup(packageInfo, OperationType.MIGRATION);
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+ OperationType.MIGRATION);
+ boolean result = eligibilityRules.appGetsFullBackup(packageInfo);
assertThat(result).isFalse();
}
@@ -424,7 +425,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.backupAgentName = null;
- boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+ boolean result = mBackupEligibilityRules.appIsKeyValueOnly(packageInfo);
assertThat(result).isFalse();
}
@@ -437,7 +438,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo.backupAgentName = "backup.agent";
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
- boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+ boolean result = mBackupEligibilityRules.appIsKeyValueOnly(packageInfo);
assertThat(result).isFalse();
}
@@ -450,7 +451,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo.backupAgentName = "backup.agent";
packageInfo.applicationInfo.flags = ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
- boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+ boolean result = mBackupEligibilityRules.appIsKeyValueOnly(packageInfo);
assertThat(result).isTrue();
}
@@ -460,8 +461,9 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = Process.SYSTEM_UID;
- boolean result = AppBackupUtils.appIgnoresIncludeExcludeRules(applicationInfo,
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
OperationType.MIGRATION);
+ boolean result = eligibilityRules.appIgnoresIncludeExcludeRules(applicationInfo);
assertThat(result).isFalse();
}
@@ -471,8 +473,9 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = Process.SYSTEM_UID;
- boolean result = AppBackupUtils.appIgnoresIncludeExcludeRules(applicationInfo,
- OperationType.BACKUP);
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
+ OperationType.MIGRATION);
+ boolean result = eligibilityRules.appIgnoresIncludeExcludeRules(applicationInfo);
assertThat(result).isFalse();
}
@@ -482,8 +485,9 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = Process.FIRST_APPLICATION_UID;
- boolean result = AppBackupUtils.appIgnoresIncludeExcludeRules(applicationInfo,
+ BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
OperationType.MIGRATION);
+ boolean result = eligibilityRules.appIgnoresIncludeExcludeRules(applicationInfo);
assertThat(result).isTrue();
}
@@ -493,16 +497,14 @@ public class AppBackupUtilsTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = Process.FIRST_APPLICATION_UID;
- boolean result = AppBackupUtils.appIgnoresIncludeExcludeRules(applicationInfo,
- OperationType.BACKUP);
+ boolean result = mBackupEligibilityRules.appIgnoresIncludeExcludeRules(applicationInfo);
assertThat(result).isFalse();
}
@Test
public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {SIGNATURE_1}, null);
assertThat(result).isFalse();
}
@@ -514,8 +516,7 @@ public class AppBackupUtilsTest {
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[0], packageInfo);
assertThat(result).isTrue();
}
@@ -533,8 +534,7 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(null, packageInfo);
assertThat(result).isFalse();
}
@@ -552,8 +552,7 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[0], packageInfo);
assertThat(result).isFalse();
}
@@ -568,8 +567,8 @@ public class AppBackupUtilsTest {
packageInfo.signingInfo = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {SIGNATURE_1},
+ packageInfo);
assertThat(result).isFalse();
}
@@ -583,8 +582,8 @@ public class AppBackupUtilsTest {
packageInfo.signingInfo = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {SIGNATURE_1},
+ packageInfo);
assertThat(result).isFalse();
}
@@ -596,8 +595,7 @@ public class AppBackupUtilsTest {
packageInfo.signingInfo = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(null, packageInfo);
assertThat(result).isFalse();
}
@@ -610,8 +608,7 @@ public class AppBackupUtilsTest {
packageInfo.signingInfo = null;
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[0], packageInfo);
assertThat(result).isFalse();
}
@@ -632,9 +629,8 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(
- new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(
+ new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo);
assertThat(result).isTrue();
}
@@ -654,9 +650,8 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature2Copy, signature1Copy}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(
+ new Signature[]{signature2Copy, signature1Copy}, packageInfo);
assertThat(result).isTrue();
}
@@ -676,9 +671,8 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(
+ new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo);
assertThat(result).isFalse();
}
@@ -698,9 +692,8 @@ public class AppBackupUtilsTest {
null));
packageInfo.applicationInfo = new ApplicationInfo();
- boolean result = AppBackupUtils.signaturesMatch(
- new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo,
- mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(
+ new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo);
assertThat(result).isFalse();
}
@@ -723,8 +716,8 @@ public class AppBackupUtilsTest {
doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
packageInfo.packageName);
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
- packageInfo, mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo);
assertThat(result).isTrue();
}
@@ -749,8 +742,8 @@ public class AppBackupUtilsTest {
doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
packageInfo.packageName);
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
- packageInfo, mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo);
assertThat(result).isTrue();
}
@@ -776,12 +769,17 @@ public class AppBackupUtilsTest {
doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
packageInfo.packageName);
- boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
- packageInfo, mMockPackageManagerInternal);
+ boolean result = mBackupEligibilityRules.signaturesMatch(new Signature[] {signature1Copy},
+ packageInfo);
assertThat(result).isFalse();
}
+ private BackupEligibilityRules getBackupEligibilityRules(@OperationType int operationType) {
+ return new BackupEligibilityRules(mPackageManager, mMockPackageManagerInternal, mUserId,
+ operationType);
+ }
+
private static Signature generateSignature(byte i) {
byte[] signatureBytes = new byte[256];
signatureBytes[0] = i;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 75e0d9144f57..a5df53205a36 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
@@ -75,6 +76,8 @@ public class AuthServiceTest {
IIrisService mIrisService;
@Mock
IFaceService mFaceService;
+ @Mock
+ AppOpsManager mAppOpsManager;
@Before
public void setUp() {
@@ -93,6 +96,7 @@ public class AuthServiceTest {
when(mInjector.getFingerprintService()).thenReturn(mFingerprintService);
when(mInjector.getFaceService()).thenReturn(mFaceService);
when(mInjector.getIrisService()).thenReturn(mIrisService);
+ when(mInjector.getAppOps(any())).thenReturn(mAppOpsManager);
}
@Test
@@ -140,7 +144,9 @@ public class AuthServiceTest {
// TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId
@Test
- public void testAuthenticate_callsBiometricServiceAuthenticate() throws Exception {
+ public void testAuthenticate_appOpsOk_callsBiometricServiceAuthenticate() throws Exception {
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_USE_BIOMETRIC), anyInt(), any(), any(),
+ any())).thenReturn(AppOpsManager.MODE_ALLOWED);
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
@@ -170,6 +176,38 @@ public class AuthServiceTest {
}
@Test
+ public void testAuthenticate_appOpsDenied_doesNotCallBiometricService() throws Exception {
+ when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_USE_BIOMETRIC), anyInt(), any(), any(),
+ any())).thenReturn(AppOpsManager.MODE_ERRORED);
+ mAuthService = new AuthService(mContext, mInjector);
+ mAuthService.onStart();
+
+ final Binder token = new Binder();
+ final PromptInfo promptInfo = new PromptInfo();
+ final long sessionId = 0;
+ final int userId = 0;
+
+ mAuthService.mImpl.authenticate(
+ token,
+ sessionId,
+ userId,
+ mReceiver,
+ TEST_OP_PACKAGE_NAME,
+ promptInfo);
+ waitForIdle();
+ verify(mBiometricService, never()).authenticate(
+ eq(token),
+ eq(sessionId),
+ eq(userId),
+ eq(mReceiver),
+ eq(TEST_OP_PACKAGE_NAME),
+ eq(promptInfo),
+ eq(Binder.getCallingUid()),
+ eq(Binder.getCallingPid()),
+ eq(UserHandle.getCallingUserId()));
+ }
+
+ @Test
public void testCanAuthenticate_callsBiometricServiceCanAuthenticate() throws Exception {
mAuthService = new AuthService(mContext, mInjector);
mAuthService.onStart();
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java
deleted file mode 100644
index 0c66ee75eab0..000000000000
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricServiceBaseTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.hardware.biometrics.BiometricAuthenticator;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-@Presubmit
-@SmallTest
-public class BiometricServiceBaseTest {
- private static class TestableBiometricServiceBase extends BiometricServiceBase {
- TestableBiometricServiceBase(Context context) {
- super(context);
- }
-
- @Override
- protected void doTemplateCleanupForUser(int userId) {
- }
-
- @Override
- protected String getTag() {
- return null;
- }
-
- @Override
- protected Object getDaemon() {
- return null;
- }
-
- @Override
- protected BiometricUtils getBiometricUtils() {
- return null;
- }
-
- @Override
- protected boolean hasReachedEnrollmentLimit(int userId) {
- return false;
- }
-
- @Override
- protected void updateActiveGroup(int userId) {
- }
-
- @Override
- protected boolean hasEnrolledBiometrics(int userId) {
- return false;
- }
-
- @Override
- protected String getManageBiometricPermission() {
- return null;
- }
-
- @Override
- protected List<? extends BiometricAuthenticator.Identifier> getEnrolledTemplates(
- int userId) {
- return null;
- }
-
- @Override
- protected int statsModality() {
- return 0;
- }
- }
-
- private static final int CLIENT_COOKIE = 0xc00c1e;
-
- private BiometricServiceBase mBiometricServiceBase;
-
- @Mock
- private Context mContext;
- @Mock
- private Resources mResources;
- @Mock
- private BiometricAuthenticator.Identifier mIdentifier;
- @Mock
- private ClientMonitor mClient;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- when(mContext.getResources()).thenReturn(mResources);
- when(mResources.getString(anyInt())).thenReturn("");
- when(mClient.getCookie()).thenReturn(CLIENT_COOKIE);
-
- mBiometricServiceBase = new TestableBiometricServiceBase(mContext);
- }
-
- @Test
- public void testHandleEnumerate_doesNotCrash_withNullClient() {
- mBiometricServiceBase.handleEnumerate(mIdentifier, 0 /* remaining */);
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index c7b45efb2de1..76b1a4d69f05 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -17,6 +17,8 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
@@ -65,9 +67,13 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import android.app.ActivityManager.TaskSnapshot;
@@ -405,7 +411,7 @@ public class ActivityRecordTests extends ActivityTestsBase {
@Test
public void ignoreRequestedOrientationInFreeformWindows() {
- mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
+ mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
final Rect stableRect = new Rect();
mStack.getDisplay().mDisplayContent.getStableRect(stableRect);
@@ -1657,6 +1663,26 @@ public class ActivityRecordTests extends ActivityTestsBase {
.diff(wpc.getRequestedOverrideConfiguration()));
}
+ @Test
+ public void testCanTurnScreenOn() {
+ mStack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ doReturn(true).when(mStack).checkKeyguardVisibility(
+ same(mActivity), eq(true) /* shouldBeVisible */, anyBoolean());
+ doReturn(true).when(mActivity).getTurnScreenOnFlag();
+
+ assertTrue(mActivity.canTurnScreenOn());
+ }
+
+ @Test
+ public void testFreeformWindowCantTurnScreenOn() {
+ mStack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ doReturn(true).when(mStack).checkKeyguardVisibility(
+ same(mActivity), eq(true) /* shouldBeVisible */, anyBoolean());
+ doReturn(true).when(mActivity).getTurnScreenOnFlag();
+
+ assertFalse(mActivity.canTurnScreenOn());
+ }
+
/**
* Creates an activity on display. For non-default display request it will also create a new
* display with custom DisplayInfo.
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 792b597d23d2..f7b7b584fae5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -950,6 +950,21 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testInputMethodInputTarget_isClearedWhenWindowStateIsRemoved() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+
+ WindowState app = createWindow(null, TYPE_BASE_APPLICATION, dc, "app");
+
+ dc.mInputMethodInputTarget = app;
+ assertEquals(app, dc.computeImeControlTarget());
+
+ app.removeImmediately();
+
+ assertNull(dc.mInputMethodInputTarget);
+ assertNull(dc.computeImeControlTarget());
+ }
+
+ @Test
public void testComputeImeControlTarget() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.setRemoteInsetsController(createDisplayWindowInsetsController());
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index f9de37994350..4ea5b97decf4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -40,8 +40,13 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DEC
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT;
+import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -63,6 +68,7 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.Gravity;
import android.view.InsetsState;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Type;
@@ -122,9 +128,14 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
updateDisplayFrames();
}
- public void setRotation(int rotation) {
+ public void setRotation(int rotation, boolean includingWindows) {
mRotation = rotation;
updateDisplayFrames();
+ if (includingWindows) {
+ mNavBarWindow.getWindowConfiguration().setRotation(rotation);
+ mStatusBarWindow.getWindowConfiguration().setRotation(rotation);
+ mWindow.getWindowConfiguration().setRotation(rotation);
+ }
}
public void addDisplayCutout() {
@@ -162,6 +173,8 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void addingWindow_withInsetsTypes() {
+ mDisplayPolicy.removeWindowLw(mStatusBarWindow); // Removes the existing one.
+
WindowState win = createWindow(null, TYPE_STATUS_BAR_SUB_PANEL, "StatusBarSubPanel");
win.mAttrs.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
win.getFrameLw().set(0, 0, 500, 100);
@@ -211,6 +224,47 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
}
@Test
+ public void addingWindow_variousGravities_alternateBarPosUpdated() {
+ mDisplayPolicy.removeWindowLw(mNavBarWindow); // Removes the existing one.
+
+ WindowState win1 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel1");
+ win1.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win1.mAttrs.gravity = Gravity.TOP;
+ win1.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win1);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_TOP);
+ mDisplayPolicy.removeWindowLw(win1);
+
+ WindowState win2 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel2");
+ win2.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win2.mAttrs.gravity = Gravity.BOTTOM;
+ win2.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win2);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_BOTTOM);
+ mDisplayPolicy.removeWindowLw(win2);
+
+ WindowState win3 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel3");
+ win3.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win3.mAttrs.gravity = Gravity.LEFT;
+ win3.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win3);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_LEFT);
+ mDisplayPolicy.removeWindowLw(win3);
+
+ WindowState win4 = createWindow(null, TYPE_NAVIGATION_BAR_PANEL, "NavBarPanel4");
+ win4.mAttrs.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR};
+ win4.mAttrs.gravity = Gravity.RIGHT;
+ win4.getFrameLw().set(0, 0, 200, 500);
+ addWindow(win4);
+
+ assertEquals(mDisplayPolicy.getAlternateNavBarPosition(), ALT_BAR_RIGHT);
+ mDisplayPolicy.removeWindowLw(win4);
+ }
+
+ @Test
public void layoutWindowLw_fitStatusBars() {
mWindow.mAttrs.setFitInsetsTypes(Type.statusBars());
addWindow(mWindow);
@@ -483,8 +537,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void layoutWindowLw_withDisplayCutout_landscape() {
addDisplayCutout();
- setRotation(ROTATION_90);
-
+ setRotation(ROTATION_90, true /* includingWindows */);
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
mWindow.mAttrs.setFitInsetsTypes(0 /* types */);
@@ -504,7 +557,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void layoutWindowLw_withDisplayCutout_seascape() {
addDisplayCutout();
- setRotation(ROTATION_270);
+ setRotation(ROTATION_270, true /* includingWindows */);
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -525,7 +578,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
addDisplayCutout();
- setRotation(ROTATION_90);
+ setRotation(ROTATION_90, true /* includingWindows */);
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -566,7 +619,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
addDisplayCutout();
- setRotation(ROTATION_90);
+ setRotation(ROTATION_90, true /* includingWindows */);
mWindow.mAttrs.flags =
FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -784,7 +837,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
@Test
public void testSimulateLayoutDisplay() {
assertSimulateLayoutSameDisplayFrames();
- setRotation(ROTATION_90);
+ setRotation(ROTATION_90, false /* includingWindows */);
assertSimulateLayoutSameDisplayFrames();
addDisplayCutout();
assertSimulateLayoutSameDisplayFrames();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 4f5b3ec8bdac..4aac47cf006a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -891,6 +891,24 @@ public class RootActivityContainerTests extends ActivityTestsBase {
assertEquals(taskDisplayArea.getTopStack(), taskDisplayArea.getRootHomeTask());
}
+ @Test
+ public void testResumeFocusedStackOnSleepingDisplay() {
+ // Create an activity on secondary display.
+ final TestDisplayContent secondDisplay = addNewDisplayContentAt(
+ DisplayContent.POSITION_TOP);
+ final ActivityStack stack = secondDisplay.getDefaultTaskDisplayArea()
+ .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+ final ActivityRecord activity = new ActivityBuilder(mService).setStack(stack).build();
+ spyOn(activity);
+ spyOn(stack);
+
+ // Cannot resumed activities on secondary display if the display should sleep.
+ doReturn(true).when(secondDisplay).shouldSleep();
+ mRootWindowContainer.resumeFocusedStacksTopActivities();
+ verify(stack, never()).resumeTopActivityUncheckedLocked(any(), any());
+ verify(activity, never()).makeActiveIfNeeded(any());
+ }
+
/**
* Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
* info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
index 31a102ae3bad..ef74861e9422 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -25,8 +25,8 @@ import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.LEFT;
import static android.view.Gravity.RIGHT;
import static android.view.Gravity.TOP;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
+import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -190,7 +190,7 @@ public class ScreenDecorWindowTests {
@Test
public void testProvidesInsetsTypes() {
- int[] providesInsetsTypes = new int[]{ITYPE_STATUS_BAR};
+ int[] providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
final View win = createWindow("StatusBarSubPanel", TOP, MATCH_PARENT, mDecorThickness, RED,
FLAG_LAYOUT_IN_SCREEN, 0, providesInsetsTypes);
@@ -199,7 +199,7 @@ public class ScreenDecorWindowTests {
private View createDecorWindow(int gravity, int width, int height) {
int[] providesInsetsTypes =
- new int[]{gravity == TOP ? ITYPE_STATUS_BAR : ITYPE_NAVIGATION_BAR};
+ new int[]{gravity == TOP ? ITYPE_CLIMATE_BAR : ITYPE_EXTRA_NAVIGATION_BAR};
return createWindow("decorWindow", gravity, width, height, RED,
FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR, providesInsetsTypes);
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 321657d5d626..9b18ec644ceb 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -215,8 +215,7 @@ public class UsageStatsService extends SystemService implements
mHandler = new H(BackgroundThread.get().getLooper());
mAppStandby = AppStandbyInternal.newAppStandbyController(
- UsageStatsService.class.getClassLoader(), getContext(),
- BackgroundThread.get().getLooper());
+ UsageStatsService.class.getClassLoader(), getContext());
mAppTimeLimit = new AppTimeLimitController(
new AppTimeLimitController.TimeLimitCallbackListener() {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index 7e8a90ccd4ad..dcaff26b79c6 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -96,7 +96,8 @@ import java.io.PrintWriter;
*/
public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
static final String TAG = "EventSequenceValidator";
-
+ /** $> adb shell 'setprop log.tag.EventSequenceValidator VERBOSE' */
+ public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private State state = State.INIT;
private long accIntentStartedEvents = 0;
@@ -255,10 +256,12 @@ public class EventSequenceValidator implements ActivityMetricsLaunchObserver {
}
private void logWarningWithStackTrace(String log) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- new Throwable("EventSequenceValidator#getStackTrace").printStackTrace(pw);
- Log.wtf(TAG, String.format("%s\n%s", log, sw));
+ if (DEBUG) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ new Throwable("EventSequenceValidator#getStackTrace").printStackTrace(pw);
+ Log.wtf(TAG, String.format("%s\n%s", log, sw));
+ }
}
}
diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt
index 4b425bd2dffa..ef94c7677a17 100644
--- a/telephony/api/system-current.txt
+++ b/telephony/api/system-current.txt
@@ -1718,7 +1718,6 @@ package android.telephony.ims.feature {
ctor @Deprecated public MmTelFeature.MmTelCapabilities(android.telephony.ims.feature.ImsFeature.Capabilities);
ctor public MmTelFeature.MmTelCapabilities(int);
method public final void addCapabilities(int);
- method public final boolean isCapable(int);
method public final void removeCapabilities(int);
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index bc987a6282c7..71a1964210b0 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -623,6 +623,10 @@ public final class TelephonyPermissions {
}
private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) {
+ if (uid == Process.SYSTEM_UID || uid == Process.PHONE_UID) {
+ // Skip the check if it's one of these special uids
+ return TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ }
final long identity = Binder.clearCallingIdentity();
try {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 8450a9018634..92e419707970 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -29,6 +29,7 @@ import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -231,7 +232,9 @@ public final class EuiccProfileInfo implements Parcelable {
mState = baseProfile.mState;
mCarrierIdentifier = baseProfile.mCarrierIdentifier;
mPolicyRules = baseProfile.mPolicyRules;
- mAccessRules = Arrays.asList(baseProfile.mAccessRules);
+ mAccessRules = baseProfile.mAccessRules == null
+ ? Collections.emptyList()
+ : Arrays.asList(baseProfile.mAccessRules);
}
/** Builds the profile instance. */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b617f6abc1d6..5ea4c7b5dac9 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2382,6 +2382,16 @@ public class CarrierConfigManager {
"call_forwarding_blocks_while_roaming_string_array";
/**
+ * Call forwarding number prefixes defined by {@link
+ * #KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY} which will be allowed while the
+ * device is reporting that it is roaming and IMS is registered over LTE or Wi-Fi.
+ * By default this value is {@code true}.
+ * @hide
+ */
+ public static final String KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+ "support_ims_call_forwarding_while_roaming_bool";
+
+ /**
* The day of the month (1-31) on which the data cycle rolls over.
* <p>
* If the current month does not have this day, the cycle will roll over at
@@ -4223,6 +4233,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false);
sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
null);
+ sDefaults.putBoolean(KEY_SUPPORT_IMS_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index c667165e7a0e..e91d6fc9d801 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -72,28 +72,20 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
/**
* Provides network support info for LTE VoPS and LTE Emergency bearer support
*/
+ @Nullable
private final LteVopsSupportInfo mLteVopsSupportInfo;
/**
- * Indicates if it's using carrier aggregation
- *
- * @hide
- */
- public boolean mIsUsingCarrierAggregation;
-
- /**
* @hide
*/
DataSpecificRegistrationInfo(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
- boolean isEnDcAvailable, LteVopsSupportInfo lteVops,
- boolean isUsingCarrierAggregation) {
+ boolean isEnDcAvailable, @Nullable LteVopsSupportInfo lteVops) {
this.maxDataCalls = maxDataCalls;
this.isDcNrRestricted = isDcNrRestricted;
this.isNrAvailable = isNrAvailable;
this.isEnDcAvailable = isEnDcAvailable;
this.mLteVopsSupportInfo = lteVops;
- this.mIsUsingCarrierAggregation = isUsingCarrierAggregation;
}
/**
@@ -102,32 +94,29 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
* @param dsri another data specific registration info
* @hide
*/
- DataSpecificRegistrationInfo(DataSpecificRegistrationInfo dsri) {
+ DataSpecificRegistrationInfo(@NonNull DataSpecificRegistrationInfo dsri) {
maxDataCalls = dsri.maxDataCalls;
isDcNrRestricted = dsri.isDcNrRestricted;
isNrAvailable = dsri.isNrAvailable;
isEnDcAvailable = dsri.isEnDcAvailable;
mLteVopsSupportInfo = dsri.mLteVopsSupportInfo;
- mIsUsingCarrierAggregation = dsri.mIsUsingCarrierAggregation;
}
- private DataSpecificRegistrationInfo(Parcel source) {
+ private DataSpecificRegistrationInfo(/* @NonNull */ Parcel source) {
maxDataCalls = source.readInt();
isDcNrRestricted = source.readBoolean();
isNrAvailable = source.readBoolean();
isEnDcAvailable = source.readBoolean();
mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
- mIsUsingCarrierAggregation = source.readBoolean();
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(/* @NonNull */ Parcel dest, int flags) {
dest.writeInt(maxDataCalls);
dest.writeBoolean(isDcNrRestricted);
dest.writeBoolean(isNrAvailable);
dest.writeBoolean(isEnDcAvailable);
mLteVopsSupportInfo.writeToParcel(dest, flags);
- dest.writeBoolean(mIsUsingCarrierAggregation);
}
@Override
@@ -144,8 +133,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
.append(" isDcNrRestricted = " + isDcNrRestricted)
.append(" isNrAvailable = " + isNrAvailable)
.append(" isEnDcAvailable = " + isEnDcAvailable)
- .append(" " + mLteVopsSupportInfo.toString())
- .append(" mIsUsingCarrierAggregation = " + mIsUsingCarrierAggregation)
+ .append(" " + mLteVopsSupportInfo)
.append(" }")
.toString();
}
@@ -153,7 +141,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
- mLteVopsSupportInfo, mIsUsingCarrierAggregation);
+ mLteVopsSupportInfo);
}
@Override
@@ -167,8 +155,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
&& this.isDcNrRestricted == other.isDcNrRestricted
&& this.isNrAvailable == other.isNrAvailable
&& this.isEnDcAvailable == other.isEnDcAvailable
- && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo)
- && this.mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation;
+ && Objects.equals(mLteVopsSupportInfo, other.mLteVopsSupportInfo);
}
public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR =
@@ -192,23 +179,4 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
return mLteVopsSupportInfo;
}
- /**
- * Set the flag indicating if using carrier aggregation.
- *
- * @param isUsingCarrierAggregation {@code true} if using carrier aggregation.
- * @hide
- */
- public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) {
- mIsUsingCarrierAggregation = isUsingCarrierAggregation;
- }
-
- /**
- * Get whether network has configured carrier aggregation or not.
- *
- * @return {@code true} if using carrier aggregation.
- * @hide
- */
- public boolean isUsingCarrierAggregation() {
- return mIsUsingCarrierAggregation;
- }
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index e0b5779cfda9..aee1e84ca356 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -218,6 +218,9 @@ public final class NetworkRegistrationInfo implements Parcelable {
@NonNull
private String mRplmn;
+ // Updated based on the accessNetworkTechnology
+ private boolean mIsUsingCarrierAggregation;
+
/**
* @param domain Network domain. Must be a {@link Domain}. For transport type
* {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
@@ -251,7 +254,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
mRegistrationState = registrationState;
mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
- mAccessNetworkTechnology = accessNetworkTechnology;
+ setAccessNetworkTechnology(accessNetworkTechnology);
mRejectCause = rejectCause;
mAvailableServices = (availableServices != null)
? new ArrayList<>(availableServices) : new ArrayList<>();
@@ -290,13 +293,11 @@ public final class NetworkRegistrationInfo implements Parcelable {
@Nullable CellIdentity cellIdentity, @Nullable String rplmn,
int maxDataCalls, boolean isDcNrRestricted,
boolean isNrAvailable, boolean isEndcAvailable,
- LteVopsSupportInfo lteVopsSupportInfo,
- boolean isUsingCarrierAggregation) {
+ LteVopsSupportInfo lteVopsSupportInfo) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
emergencyOnly, availableServices, cellIdentity, rplmn);
mDataSpecificInfo = new DataSpecificRegistrationInfo(
- maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo,
- isUsingCarrierAggregation);
+ maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
updateNrState();
}
@@ -317,6 +318,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
DataSpecificRegistrationInfo.class.getClassLoader());
mNrState = source.readInt();
mRplmn = source.readString();
+ mIsUsingCarrierAggregation = source.readBoolean();
}
/**
@@ -331,6 +333,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
mRegistrationState = nri.mRegistrationState;
mRoamingType = nri.mRoamingType;
mAccessNetworkTechnology = nri.mAccessNetworkTechnology;
+ mIsUsingCarrierAggregation = nri.mIsUsingCarrierAggregation;
mRejectCause = nri.mRejectCause;
mEmergencyOnly = nri.mEmergencyOnly;
mAvailableServices = new ArrayList<>(nri.mAvailableServices);
@@ -484,9 +487,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) {
// For old device backward compatibility support
tech = TelephonyManager.NETWORK_TYPE_LTE;
- if (mDataSpecificInfo != null) {
- mDataSpecificInfo.setIsUsingCarrierAggregation(true);
- }
+ mIsUsingCarrierAggregation = true;
}
mAccessNetworkTechnology = tech;
}
@@ -511,6 +512,27 @@ public final class NetworkRegistrationInfo implements Parcelable {
}
/**
+ * Set whether network has configured carrier aggregation or not.
+ *
+ * @param isUsingCarrierAggregation set whether or not carrier aggregation is used.
+ *
+ * @hide
+ */
+ public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) {
+ mIsUsingCarrierAggregation = isUsingCarrierAggregation;
+ }
+
+ /**
+ * Get whether network has configured carrier aggregation or not.
+ *
+ * @return {@code true} if using carrier aggregation.
+ * @hide
+ */
+ public boolean isUsingCarrierAggregation() {
+ return mIsUsingCarrierAggregation;
+ }
+
+ /**
* @hide
*/
@Nullable
@@ -617,6 +639,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
.append(" dataSpecificInfo=").append(mDataSpecificInfo)
.append(" nrState=").append(nrStateToString(mNrState))
.append(" rRplmn=").append(mRplmn)
+ .append(" isUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append("}").toString();
}
@@ -624,7 +647,8 @@ public final class NetworkRegistrationInfo implements Parcelable {
public int hashCode() {
return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn);
+ mCellIdentity, mVoiceSpecificInfo, mDataSpecificInfo, mNrState, mRplmn,
+ mIsUsingCarrierAggregation);
}
@Override
@@ -644,6 +668,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
&& mAvailableServices.equals(other.mAvailableServices)
+ && mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation
&& Objects.equals(mCellIdentity, other.mCellIdentity)
&& Objects.equals(mVoiceSpecificInfo, other.mVoiceSpecificInfo)
&& Objects.equals(mDataSpecificInfo, other.mDataSpecificInfo)
@@ -670,6 +695,7 @@ public final class NetworkRegistrationInfo implements Parcelable {
dest.writeParcelable(mDataSpecificInfo, 0);
dest.writeInt(mNrState);
dest.writeString(mRplmn);
+ dest.writeBoolean(mIsUsingCarrierAggregation);
}
/**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9e2ba6875577..3e7464739f9f 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1412,29 +1412,14 @@ public class ServiceState implements Parcelable {
/** @hide */
public boolean isUsingCarrierAggregation() {
- boolean isUsingCa = false;
- NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- if (nri != null) {
- DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
- if (dsri != null) {
- isUsingCa = dsri.isUsingCarrierAggregation();
- }
- }
- return isUsingCa || getCellBandwidths().length > 1;
- }
+ if (getCellBandwidths().length > 1) return true;
- /** @hide */
- public void setIsUsingCarrierAggregation(boolean ca) {
- NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
- if (nri != null) {
- DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
- if (dsri != null) {
- dsri.setIsUsingCarrierAggregation(ca);
- addNetworkRegistrationInfo(nri);
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo nri : mNetworkRegistrationInfos) {
+ if (nri.isUsingCarrierAggregation()) return true;
}
}
+ return false;
}
/**
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index b376660f839e..183fdcce1ca4 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -670,10 +670,12 @@ public final class SmsManager {
}
if (priority < 0x00 || priority > 0x03) {
+ Log.e(TAG, "Invalid Priority " + priority);
priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
}
if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ Log.e(TAG, "Invalid Validity Period " + validityPeriod);
validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
}
@@ -1231,10 +1233,12 @@ public final class SmsManager {
}
if (priority < 0x00 || priority > 0x03) {
+ Log.e(TAG, "Invalid Priority " + priority);
priority = SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
}
if (validityPeriod < 0x05 || validityPeriod > 0x09b0a0) {
+ Log.e(TAG, "Invalid Validity Period " + validityPeriod);
validityPeriod = SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d96e024d4c60..f9148d0c44c4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -113,8 +113,6 @@ import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.SmsApplication;
import com.android.telephony.Rlog;
-import java.io.FileInputStream;
-import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -127,8 +125,6 @@ import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* Provides access to information about the telephony services on
@@ -2540,7 +2536,8 @@ public class TelephonyManager {
return PhoneConstants.PHONE_TYPE_CDMA;
case RILConstants.NETWORK_MODE_LTE_ONLY:
- if (getLteOnCdmaModeStatic() == PhoneConstants.LTE_ON_CDMA_TRUE) {
+ if (TelephonyProperties.lte_on_cdma_device().orElse(
+ PhoneConstants.LTE_ON_CDMA_FALSE) == PhoneConstants.LTE_ON_CDMA_TRUE) {
return PhoneConstants.PHONE_TYPE_CDMA;
} else {
return PhoneConstants.PHONE_TYPE_GSM;
@@ -2551,35 +2548,6 @@ public class TelephonyManager {
}
/**
- * The contents of the /proc/cmdline file
- */
- @UnsupportedAppUsage
- private static String getProcCmdLine()
- {
- String cmdline = "";
- FileInputStream is = null;
- try {
- is = new FileInputStream("/proc/cmdline");
- byte [] buffer = new byte[2048];
- int count = is.read(buffer);
- if (count > 0) {
- cmdline = new String(buffer, 0, count);
- }
- } catch (IOException e) {
- Rlog.d(TAG, "No /proc/cmdline exception=" + e);
- } finally {
- if (is != null) {
- try {
- is.close();
- } catch (IOException e) {
- }
- }
- }
- Rlog.d(TAG, "/proc/cmdline=" + cmdline);
- return cmdline;
- }
-
- /**
* @return The max value for the timeout passed in {@link #requestNumberVerification}.
* @hide
*/
@@ -2588,56 +2556,6 @@ public class TelephonyManager {
return MAX_NUMBER_VERIFICATION_TIMEOUT_MILLIS;
}
- /** Kernel command line */
- private static final String sKernelCmdLine = getProcCmdLine();
-
- /** Pattern for selecting the product type from the kernel command line */
- private static final Pattern sProductTypePattern =
- Pattern.compile("\\sproduct_type\\s*=\\s*(\\w+)");
-
- /** The ProductType used for LTE on CDMA devices */
- private static final String sLteOnCdmaProductType =
- TelephonyProperties.lte_on_cdma_product_type().orElse("");
-
- /**
- * Return if the current radio is LTE on CDMA. This
- * is a tri-state return value as for a period of time
- * the mode may be unknown.
- *
- * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE}
- * or {@link PhoneConstants#LTE_ON_CDMA_TRUE}
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static int getLteOnCdmaModeStatic() {
- int retVal;
- int curVal;
- String productType = "";
-
- curVal = TelephonyProperties.lte_on_cdma_device().orElse(
- PhoneConstants.LTE_ON_CDMA_UNKNOWN);
- retVal = curVal;
- if (retVal == PhoneConstants.LTE_ON_CDMA_UNKNOWN) {
- Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
- if (matcher.find()) {
- productType = matcher.group(1);
- if (sLteOnCdmaProductType.equals(productType)) {
- retVal = PhoneConstants.LTE_ON_CDMA_TRUE;
- } else {
- retVal = PhoneConstants.LTE_ON_CDMA_FALSE;
- }
- } else {
- retVal = PhoneConstants.LTE_ON_CDMA_FALSE;
- }
- }
-
- Rlog.d(TAG, "getLteOnCdmaMode=" + retVal + " curVal=" + curVal +
- " product_type='" + productType +
- "' lteOnCdmaProductType='" + sLteOnCdmaProductType + "'");
- return retVal;
- }
-
//
//
// Current Network
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 01d468cb53f6..d8a10ebb7bde 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -285,8 +285,8 @@ public class MmTelFeature extends ImsFeature {
public static final int CAPABILITY_TYPE_SMS = 1 << 3;
/**
- * @hide
- */
+ * @hide
+ */
@Override
@SystemApi @TestApi
public final void addCapabilities(@MmTelCapability int capabilities) {
@@ -294,8 +294,8 @@ public class MmTelFeature extends ImsFeature {
}
/**
- * @hide
- */
+ * @hide
+ */
@Override
@SystemApi @TestApi
public final void removeCapabilities(@MmTelCapability int capability) {
@@ -303,17 +303,18 @@ public class MmTelFeature extends ImsFeature {
}
/**
- * @hide
- */
+ * @param capabilities a bitmask of one or more capabilities.
+ *
+ * @return true if all queried capabilities are true, otherwise false.
+ */
@Override
- @SystemApi @TestApi
public final boolean isCapable(@MmTelCapability int capabilities) {
return super.isCapable(capabilities);
}
/**
- * @hide
- */
+ * @hide
+ */
@NonNull
@Override
public String toString() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index c7ad2bbb043f..d186fcf63cfe 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -1100,7 +1100,7 @@ public final class BearerData {
bData.hasUserDataHeader = (inStream.read(1) == 1);
inStream.skip(3);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1469,7 +1469,7 @@ public final class BearerData {
bData.reportReq = (inStream.read(1) == 1);
inStream.skip(4);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "REPLY_OPTION decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1488,7 +1488,7 @@ public final class BearerData {
decodeSuccess = true;
bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1507,7 +1507,7 @@ public final class BearerData {
decodeSuccess = true;
bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1594,7 +1594,7 @@ public final class BearerData {
bData.errorClass = inStream.read(2);
bData.messageStatus = inStream.read(6);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1614,7 +1614,7 @@ public final class BearerData {
decodeSuccess = true;
bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1633,7 +1633,7 @@ public final class BearerData {
decodeSuccess = true;
bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1653,7 +1653,7 @@ public final class BearerData {
bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
inStream.readByteArray(6 * 8));
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1672,7 +1672,7 @@ public final class BearerData {
decodeSuccess = true;
bData.deferredDeliveryTimeRelative = inStream.read(8);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1692,7 +1692,7 @@ public final class BearerData {
decodeSuccess = true;
bData.validityPeriodRelative = inStream.read(8);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1713,7 +1713,7 @@ public final class BearerData {
bData.privacy = inStream.read(2);
inStream.skip(6);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1733,7 +1733,7 @@ public final class BearerData {
decodeSuccess = true;
bData.language = inStream.read(8);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1754,7 +1754,7 @@ public final class BearerData {
bData.displayMode = inStream.read(2);
inStream.skip(6);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1775,7 +1775,7 @@ public final class BearerData {
bData.priority = inStream.read(2);
inStream.skip(6);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1796,7 +1796,7 @@ public final class BearerData {
bData.alert = inStream.read(2);
inStream.skip(6);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1816,7 +1816,7 @@ public final class BearerData {
decodeSuccess = true;
bData.userResponseCode = inStream.read(8);
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ")");
@@ -1878,7 +1878,7 @@ public final class BearerData {
decodeSuccess = true;
}
- if ((! decodeSuccess) || (paramBits > 0)) {
+ if ((!decodeSuccess) || (paramBits > 0)) {
Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
(decodeSuccess ? "succeeded" : "failed") +
" (extra bits = " + paramBits + ')');
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index f297ba74914e..7e31c4633050 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -92,14 +92,15 @@ public class SmsMessage extends SmsMessageBase {
private int mVoiceMailCount = 0;
+ /** TP-Validity-Period-Format (TP-VPF). See TS 23.040, 9.2.3.3 */
private static final int VALIDITY_PERIOD_FORMAT_NONE = 0x00;
private static final int VALIDITY_PERIOD_FORMAT_ENHANCED = 0x01;
private static final int VALIDITY_PERIOD_FORMAT_RELATIVE = 0x02;
private static final int VALIDITY_PERIOD_FORMAT_ABSOLUTE = 0x03;
- //Validity Period min - 5 mins
+ // Validity Period min - 5 mins
private static final int VALIDITY_PERIOD_MIN = 5;
- //Validity Period max - 63 weeks
+ // Validity Period max - 63 weeks
private static final int VALIDITY_PERIOD_MAX = 635040;
private static final int INVALID_VALIDITY_PERIOD = -1;
@@ -193,20 +194,20 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get Encoded Relative Validty Period Value from Validity period in mins.
+ * Gets Encoded Relative Validity Period Value from Validity period in mins.
*
* @param validityPeriod Validity period in mins.
*
* Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
- * ||relValidityPeriod (TP-VP) || || validityPeriod ||
- *
- * 0 to 143 ---> (TP-VP + 1) x 5 minutes
- *
- * 144 to 167 ---> 12 hours + ((TP-VP -143) x 30 minutes)
- *
- * 168 to 196 ---> (TP-VP - 166) x 1 day
- *
- * 197 to 255 ---> (TP-VP - 192) x 1 week
+ * ------------------------------------------------------------
+ * TP-VP | Validity period
+ * (Relative format) | value
+ * ------------------------------------------------------------
+ * 0 to 143 | (TP-VP + 1) x 5 minutes
+ * 144 to 167 | 12 hours + ((TP-VP -143) x 30 minutes)
+ * 168 to 196 | (TP-VP - 166) x 1 day
+ * 197 to 255 | (TP-VP - 192) x 1 week
+ * ------------------------------------------------------------
*
* @return relValidityPeriod Encoded Relative Validity Period Value.
* @hide
@@ -214,19 +215,16 @@ public class SmsMessage extends SmsMessageBase {
public static int getRelativeValidityPeriod(int validityPeriod) {
int relValidityPeriod = INVALID_VALIDITY_PERIOD;
- if (validityPeriod < VALIDITY_PERIOD_MIN || validityPeriod > VALIDITY_PERIOD_MAX) {
- Rlog.e(LOG_TAG,"Invalid Validity Period" + validityPeriod);
- return relValidityPeriod;
- }
-
- if (validityPeriod <= 720) {
- relValidityPeriod = (validityPeriod / 5) - 1;
- } else if (validityPeriod <= 1440) {
- relValidityPeriod = ((validityPeriod - 720) / 30) + 143;
- } else if (validityPeriod <= 43200) {
- relValidityPeriod = (validityPeriod / 1440) + 166;
- } else if (validityPeriod <= 635040) {
- relValidityPeriod = (validityPeriod / 10080) + 192;
+ if (validityPeriod >= VALIDITY_PERIOD_MIN) {
+ if (validityPeriod <= 720) {
+ relValidityPeriod = (validityPeriod / 5) - 1;
+ } else if (validityPeriod <= 1440) {
+ relValidityPeriod = ((validityPeriod - 720) / 30) + 143;
+ } else if (validityPeriod <= 43200) {
+ relValidityPeriod = (validityPeriod / 1440) + 166;
+ } else if (validityPeriod <= VALIDITY_PERIOD_MAX) {
+ relValidityPeriod = (validityPeriod / 10080) + 192;
+ }
}
return relValidityPeriod;
}
@@ -336,17 +334,19 @@ public class SmsMessage extends SmsMessageBase {
SubmitPdu ret = new SubmitPdu();
- int validityPeriodFormat = VALIDITY_PERIOD_FORMAT_NONE;
- int relativeValidityPeriod = INVALID_VALIDITY_PERIOD;
+ int relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod);
+
+ byte mtiByte = 0x01; // SMS-SUBMIT
- // TP-Validity-Period-Format (TP-VPF) in 3GPP TS 23.040 V6.8.1 section 9.2.3.3
- //bit 4:3 = 10 - TP-VP field present - relative format
- if((relativeValidityPeriod = getRelativeValidityPeriod(validityPeriod)) >= 0) {
- validityPeriodFormat = VALIDITY_PERIOD_FORMAT_RELATIVE;
+ if (header != null) {
+ // Set TP-UDHI
+ mtiByte |= 0x40;
}
- byte mtiByte = (byte)(0x01 | (validityPeriodFormat << 0x03) |
- (header != null ? 0x40 : 0x00));
+ if (relativeValidityPeriod != INVALID_VALIDITY_PERIOD) {
+ // Set TP-Validity-Period-Format (TP-VPF)
+ mtiByte |= VALIDITY_PERIOD_FORMAT_RELATIVE << 3;
+ }
ByteArrayOutputStream bo = getSubmitPduHead(
scAddress, destinationAddress, mtiByte,
@@ -418,8 +418,8 @@ public class SmsMessage extends SmsMessageBase {
bo.write(0x08);
}
- if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) {
- // ( TP-Validity-Period - relative format)
+ // TP-Validity-Period (TP-VP)
+ if (relativeValidityPeriod != INVALID_VALIDITY_PERIOD) {
bo.write(relativeValidityPeriod);
}
@@ -1352,23 +1352,17 @@ public class SmsMessage extends SmsMessageBase {
// TP-Validity-Period-Format
int validityPeriodLength = 0;
- int validityPeriodFormat = ((firstByte>>3) & 0x3);
- if (0x0 == validityPeriodFormat) /* 00, TP-VP field not present*/
- {
+ int validityPeriodFormat = ((firstByte >> 3) & 0x3);
+ if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_NONE) {
validityPeriodLength = 0;
- }
- else if (0x2 == validityPeriodFormat) /* 10, TP-VP: relative format*/
- {
+ } else if (validityPeriodFormat == VALIDITY_PERIOD_FORMAT_RELATIVE) {
validityPeriodLength = 1;
- }
- else /* other case, 11 or 01, TP-VP: absolute or enhanced format*/
- {
+ } else { // VALIDITY_PERIOD_FORMAT_ENHANCED or VALIDITY_PERIOD_FORMAT_ABSOLUTE
validityPeriodLength = 7;
}
// TP-Validity-Period is not used on phone, so just ignore it for now.
- while (validityPeriodLength-- > 0)
- {
+ while (validityPeriodLength-- > 0) {
p.getByte();
}
diff --git a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
index ba2064005937..e1b508b424f5 100644
--- a/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
+++ b/tests/ActivityManagerPerfTests/tests/src/com/android/frameworks/perftests/am/tests/ServiceStartPerfTest.java
@@ -25,14 +25,30 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.perftests.am.util.Constants;
import com.android.frameworks.perftests.am.util.TargetPackageUtils;
+import com.android.frameworks.perftests.am.util.Utils;
+import org.junit.After;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ServiceStartPerfTest extends BasePerfTest {
+ private static final String STUB_PACKAGE_NAME =
+ "com.android.frameworks.perftests.amteststestapp";
+
+ @Before
+ public void setUp() {
+ super.setUp();
+ Utils.runShellCommand("cmd deviceidle whitelist +" + STUB_PACKAGE_NAME);
+ }
+
+ @After
+ public void tearDown() {
+ Utils.runShellCommand("cmd deviceidle whitelist -" + STUB_PACKAGE_NAME);
+ }
/**
* Tries to start the service with the given intent, throwing a RuntimeException with the
diff --git a/tests/FlickerTests/AndroidManifest.xml b/tests/FlickerTests/AndroidManifest.xml
index e0bd66580ec4..98e02ced8d0b 100644
--- a/tests/FlickerTests/AndroidManifest.xml
+++ b/tests/FlickerTests/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker">
- <uses-sdk android:minSdkVersion="27" android:targetSdkVersion="27"/>
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
<!-- Read and write traces from external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index d83ee3a29381..58df2a806a1e 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -33,7 +33,7 @@
<option name="hidden-api-checks" value="false" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
- <option name="directory-keys" value="/sdcard/flicker" />
+ <option name="directory-keys" value="/storage/emulated/0/Android/data/com.android.server.wm.flicker/files" />
<option name="collect-on-run-ended-only" value="true" />
<option name="clean-up" value="true" />
</metrics_collector>
diff --git a/tests/FlickerTests/README.md b/tests/FlickerTests/README.md
index a7c9e20e0a07..6b28fdf8a8ef 100644
--- a/tests/FlickerTests/README.md
+++ b/tests/FlickerTests/README.md
@@ -1,146 +1,88 @@
# Flicker Test Library
## Motivation
-Detect *flicker* &mdash; any discontinuous, or unpredictable behavior seen during UI transitions that is not due to performance. This is often the result of a logic error in the code and difficult to identify because the issue is transient and at times difficult to reproduce. This library helps create integration tests between `SurfaceFlinger`, `WindowManager` and `SystemUI` to identify flicker.
+This set of tests use the flickerlib from `platform_testing/libraries/flicker` to execute a set of common UI transitions to detect discontinuous or unpredictable behavior.
-## Adding a Test
-The library builds and runs UI transitions, captures Winscope traces and exposes common assertions that can be tested against each trace.
-
-### Building Transitions
-Start by defining common or error prone transitions using `TransitionRunner`.
-```java
-// Example: Build a transition that cold launches an app from launcher
-TransitionRunner transition = TransitionRunner.newBuilder()
- // Specify a tag to identify the transition (optional)
- .withTag("OpenAppCold_" + testApp.getLauncherName())
-
- // Specify preconditions to setup the device
- // Wake up device and go to home screen
- .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
-
- // Setup transition under test
- // Press the home button and close the app to test a cold start
- .runBefore(device::pressHome)
- .runBefore(testApp::exit)
-
- // Run the transition under test
- // Open the app and wait for UI to be idle
- // This is the part of the transition that will be tested.
- .run(testApp::open)
- .run(device::waitForIdle)
-
- // Perform any tear downs
- // Close the app
- .runAfterAll(testApp::exit)
-
- // Number of times to repeat the transition to catch any flaky issues
- .repeat(5);
-```
-
-
-Run the transition to get a list of `TransitionResult` for each time the transition is repeated.
-```java
- List<TransitionResult> results = transition.run();
-```
-`TransitionResult` contains paths to test artifacts such as Winscope traces and screen recordings.
-
-
-### Checking Assertions
-Each `TransitionResult` can be tested using an extension of the Google Truth library, `LayersTraceSubject` and `WmTraceSubject`. They try to balance test principles set out by Google Truth (not supporting nested assertions, keeping assertions simple) with providing support for common assertion use cases.
-
-Each trace can be represented as a ordered collection of trace entries, with an associated timestamp. Each trace entry has common assertion checks. The trace subjects expose methods to filter the range of entries and test for changing assertions.
-
-```java
- TransitionResult result = results.get(0);
- Rect displayBounds = getDisplayBounds();
+The tests are organized in packages according to the transitions they test (e.g., `rotation`, `splitscreen`).
- // check all trace entries
- assertThat(result).coversRegion(displayBounds).forAllEntries();
-
- // check a range of entries
- assertThat(result).coversRegion(displayBounds).forRange(startTime, endTime);
-
- // check first entry
- assertThat(result).coversRegion(displayBounds).inTheBeginning();
+## Adding a Test
- // check last entry
- assertThat(result).coversRegion(displayBounds).atTheEnd();
+By default tests should inherit from `RotationTestBase` or `NonRotationTestBase` and must override the variable `transitionToRun` (Kotlin) or the function `getTransitionToRun()` (Java).
+Only tests that are not supported by these classes should inherit directly from the `FlickerTestBase` class.
- // check a change in assertions, e.g. wallpaper window is visible,
- // then wallpaper window becomes and stays invisible
- assertThat(result)
- .showsBelowAppWindow("wallpaper")
- .then()
- .hidesBelowAppWindow("wallpaper")
- .forAllEntries();
-```
+### Rotation animations and transitions
-All assertions return `Result` which contains a `success` flag, `assertionName` string identifier, and `reason` string to provide actionable details to the user. The `reason` string is build along the way with all the details as to why the assertions failed and any hints which might help the user determine the root cause. Failed assertion message will also contain a path to the trace that was tested. Example of a failed test:
+Tests that rotate the device should inherit from `RotationTestBase`.
+Tests that inherit from the class automatically receive start and end rotation values.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* status bar rotates
+* nav bar is always visible
+* nav bar is rotates
-```
- java.lang.AssertionError: Not true that <com.android.server.wm.flicker.LayersTrace@65da4cc>
- Layers Trace can be found in: /layers_trace_emptyregion.pb
- Timestamp: 2308008331271
- Assertion: coversRegion
- Reason: Region to test: Rect(0, 0 - 1440, 2880)
- first empty point: 0, 99
- visible regions:
- StatusBar#0Rect(0, 0 - 1440, 98)
- NavigationBar#0Rect(0, 2712 - 1440, 2880)
- ScreenDecorOverlay#0Rect(0, 0 - 1440, 91)
- ...
- at com.google.common.truth.FailureStrategy.fail(FailureStrategy.java:24)
- ...
-```
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Non-Rotation animations and transitions
-## Running Tests
+`NonRotationTestBase` was created to make it easier to write tests that do not involve rotation (e.g., `Pip`, `split screen` or `IME`).
+Tests that inherit from the class are automatically executed twice: once in portrait and once in landscape mode and the assertions are checked independently.
+Moreover, these tests inherit the following checks:
+* all regions on the screen are covered
+* status bar is always visible
+* nav bar is always visible
-The tests can be run as any other Android JUnit tests. `platform_testing/tests/flicker` uses the library to test common UI transitions. Run `atest FlickerTest` to execute these tests.
+The default tests can be disabled by overriding the respective methods and including an `@Ignore` annotation.
----
+### Exceptional cases
-## Other Topics
-### Monitors
-Monitors capture test artifacts for each transition run. They are started before each iteration of the test transition (after the `runBefore` calls) and stopped after the transition is completed. Each iteration will produce a new test artifact. The following monitors are available:
+Tests that rotate the device should inherit from `RotationTestBase`.
+This class allows the test to be freely configured and does not provide any assertions.
-#### LayersTraceMonitor
-Captures Layers trace. This monitor is started by default. Build a transition with `skipLayersTrace()` to disable this monitor.
-#### WindowManagerTraceMonitor
-Captures Window Manager trace. This monitor is started by default. Build a transition with `skipWindowManagerTrace()` to disable this monitor.
-#### WindowAnimationFrameStatsMonitor
-Captures WindowAnimationFrameStats for the transition. This monitor is started by default and is used to eliminate *janky* runs. If an iteration has skipped frames, as determined by WindowAnimationFrameStats, the results for the iteration is skipped. If the list of results is empty after all iterations are completed, then the test should fail. Build a transition with `includeJankyRuns()` to disable this monitor.
-#### ScreenRecorder
-Captures screen to a video file. This monitor is disabled by default. Build a transition with `recordEachRun()` to capture each transition or build with `recordAllRuns()` to capture every transition including setup and teardown.
----
+### Example
-### Extending Assertions
-
-To add a new assertion, add a function to one of the trace entry classes, `LayersTrace.Entry` or `WindowManagerTrace.Entry`.
+Start by defining common or error prone transitions using `TransitionRunner`.
+```kotlin
+@LargeTest
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class MyTest(
+ beginRotationName: String,
+ beginRotation: Int
+) : NonRotationTestBase(beginRotationName, beginRotation) {
+ init {
+ mTestApp = MyAppHelper(InstrumentationRegistry.getInstrumentation())
+ }
-```java
- // Example adds an assertion to the check if layer is hidden by parent.
- Result isHiddenByParent(String layerName) {
- // Result should contain a details if assertion fails for any reason
- // such as if layer is not found or layer is not hidden by parent
- // or layer has no parent.
- // ...
+ override val transitionToRun: TransitionRunner
+ get() = TransitionRunner.newBuilder()
+ .withTag("myTest")
+ .recordAllRuns()
+ .runBefore { device.pressHome() }
+ .runBefore { device.waitForIdle() }
+ .run { testApp.open() }
+ .runAfter{ testApp.exit() }
+ .repeat(2)
+ .includeJankyRuns()
+ .build()
+
+ @Test
+ fun myWMTest() {
+ checkResults {
+ WmTraceSubject.assertThat(it)
+ .showsAppWindow(MyTestApp)
+ .forAllEntries()
+ }
}
-```
-Then add a function to the trace subject `LayersTraceSubject` or `WmTraceSubject` which will add the assertion for testing. When the assertion is evaluated, the trace will first be filtered then the assertion will be applied to the remaining entries.
-```java
- public LayersTraceSubject isHiddenByParent(String layerName) {
- mChecker.add(entry -> entry.isHiddenByParent(layerName),
- "isHiddenByParent(" + layerName + ")");
- return this;
+ @Test
+ fun mySFTest() {
+ checkResults {
+ LayersTraceSubject.assertThat(it)
+ .showsLayer(MyTestApp)
+ .forAllEntries()
+ }
}
+}
```
-
-To use the new assertion:
-```java
- // Check if "Chrome" layer is hidden by parent in the first trace entry.
- assertThat(result).isHiddenByParent("Chrome").inTheBeginning();
-``` \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 7b155ebd93e1..ed8bd2a5fe83 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -55,9 +55,9 @@ open class CloseImeWindowToHomeTest(
open fun checkVisibility_imeWindowBecomesInvisible() {
checkResults {
WmTraceSubject.assertThat(it)
- .showsImeWindow(IME_WINDOW_TITLE)
+ .showsNonAppWindow(IME_WINDOW_TITLE)
.then()
- .hidesImeWindow(IME_WINDOW_TITLE)
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
.forAllEntries()
}
}
@@ -96,7 +96,7 @@ open class CloseImeWindowToHomeTest(
WmTraceSubject.assertThat(it)
.showsAppWindowOnTop(testApp.getPackage())
.then()
- .hidesAppWindowOnTop(testApp.getPackage())
+ .appWindowNotOnTop(testApp.getPackage())
.forAllEntries()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 9885359a0fb7..c7731f330aeb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -54,9 +54,9 @@ class OpenImeWindowTest(
checkResults {
WmTraceSubject.assertThat(it)
.skipUntilFirstAssertion()
- .hidesImeWindow(IME_WINDOW_TITLE)
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
.then()
- .showsImeWindow(IME_WINDOW_TITLE)
+ .showsNonAppWindow(IME_WINDOW_TITLE)
.forAllEntries()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index bfececa72d4e..f939a7915e74 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -58,7 +58,7 @@ class PipToAppTest(
.then()
.showsAppWindowOnTop(testApp.getPackage())
.then()
- .hidesAppWindowOnTop(testApp.getPackage())
+ .appWindowNotOnTop(testApp.getPackage())
.forAllEntries()
}
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 7770c73d7a73..4d2144061ad4 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.wm.flicker.testapp">
- <uses-sdk android:minSdkVersion="17"
- android:targetSdkVersion="27"/>
+ <uses-sdk android:minSdkVersion="29"
+ android:targetSdkVersion="29"/>
<application android:allowBackup="false"
android:supportsRtl="true">
<activity android:name=".SimpleActivity"
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index a23df920b396..4f5a30502c91 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -53,6 +53,9 @@ java_test_host {
name: "MultiUserRollbackTest",
srcs: ["MultiUserRollbackTest/src/**/*.java"],
libs: ["tradefed"],
+ static_libs: [
+ "frameworks-base-hostutils",
+ ],
test_suites: ["general-tests"],
test_config: "MultiUserRollbackTest.xml",
}
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index 42b886f0774f..741745560c61 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -24,6 +24,7 @@ import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,6 +41,9 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
+ @Rule
+ public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
+
@After
public void tearDown() throws Exception {
removeSecondaryUserIfNecessary();
@@ -59,6 +63,37 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
runPhaseForUsers("testBasic", mSecondaryUserId);
}
+ /**
+ * Tests staged install/rollback works correctly on the 2nd user.
+ */
+ @Test
+ public void testStagedRollback() throws Exception {
+ runPhaseForUsers("testStagedRollback_Phase1", mSecondaryUserId);
+ getDevice().reboot();
+
+ // Need to unlock the user for device tests to run successfully
+ getDevice().startUser(mSecondaryUserId);
+ awaitUserUnlocked(mSecondaryUserId);
+ runPhaseForUsers("testStagedRollback_Phase2", mSecondaryUserId);
+ getDevice().reboot();
+
+ getDevice().startUser(mSecondaryUserId);
+ awaitUserUnlocked(mSecondaryUserId);
+ runPhaseForUsers("testStagedRollback_Phase3", mSecondaryUserId);
+ getDevice().reboot();
+
+ getDevice().startUser(mSecondaryUserId);
+ awaitUserUnlocked(mSecondaryUserId);
+ runPhaseForUsers("testStagedRollback_Phase4", mSecondaryUserId);
+ }
+
+ @Test
+ public void testBadUpdateRollback() throws Exception {
+ // Need to switch user in order to send broadcasts in device tests
+ assertTrue(getDevice().switchUser(mSecondaryUserId));
+ runPhaseForUsers("testBadUpdateRollback", mSecondaryUserId);
+ }
+
@Test
public void testMultipleUsers() throws Exception {
runPhaseForUsers("testMultipleUsersInstallV1", mOriginalUserId, mSecondaryUserId);
@@ -83,6 +118,8 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private void removeSecondaryUserIfNecessary() throws Exception {
if (mSecondaryUserId != -1) {
+ // Can't remove the 2nd user without switching out of it
+ assertTrue(getDevice().switchUser(mOriginalUserId));
getDevice().removeUser(mSecondaryUserId);
mSecondaryUserId = -1;
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 8641f4d4013a..d37dd7b9ceab 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -70,6 +70,11 @@ public class MultiUserRollbackTest {
new RollbackTest().testBasic();
}
+ @Test
+ public void testBadUpdateRollback() throws Exception {
+ new RollbackTest().testBadUpdateRollback();
+ }
+
/**
* Install version 1 of the test app. This method is run for both users.
*/
@@ -115,4 +120,32 @@ public class MultiUserRollbackTest {
assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
InstallUtils.processUserData(TestApp.A);
}
+
+ @Test
+ public void testStagedRollback_Phase1() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).setStaged().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ }
+
+ @Test
+ public void testStagedRollback_Phase2() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ }
+
+ @Test
+ public void testStagedRollback_Phase3() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ RollbackInfo rollback = RollbackUtils.waitForAvailableRollback(TestApp.A);
+ assertThat(rollback).packagesContainsExactly(Rollback.from(TestApp.A2).to(TestApp.A1));
+ RollbackUtils.rollback(rollback.getRollbackId());
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2);
+ }
+
+ @Test
+ public void testStagedRollback_Phase4() {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ }
}
diff --git a/tests/benchmarks/internal/Android.bp b/tests/benchmarks/internal/Android.bp
new file mode 100644
index 000000000000..9c34eaf2af01
--- /dev/null
+++ b/tests/benchmarks/internal/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "InternalBenchTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ ],
+ test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform"
+}
+
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/tests/benchmarks/internal/AndroidManifest.xml
index 6a0695e817c7..16023c6f3617 100644
--- a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
+++ b/tests/benchmarks/internal/AndroidManifest.xml
@@ -13,7 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@color/transparent" />
- <item android:drawable="@drawable/floating_dismiss_gradient" />
-</transition> \ No newline at end of file
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.internal.bench">
+
+ <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.bench"/>
+</manifest>
+
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/tests/benchmarks/internal/AndroidTest.xml
index 0db1a57a0973..d776ee681c04 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/tests/benchmarks/internal/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2020 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,6 +13,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<configuration description="Benchmark for internal classes/utilities.">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="InternalBenchTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.internal.bench" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+</configuration>
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
new file mode 100644
index 000000000000..388548691b77
--- /dev/null
+++ b/tests/benchmarks/internal/src/com/android/internal/LambdaPerfTest.java
@@ -0,0 +1,454 @@
+/*
+ * 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;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledPredicate;
+
+import org.junit.Assume;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Compares the performance of regular lambda and pooled lambda. */
+@LargeTest
+public class LambdaPerfTest {
+ private static final boolean DEBUG = false;
+ private static final String TAG = LambdaPerfTest.class.getSimpleName();
+
+ private static final String LAMBDA_FORM_REGULAR = "regular";
+ private static final String LAMBDA_FORM_POOLED = "pooled";
+
+ private static final int WARMUP_ITERATIONS = 1000;
+ private static final int TEST_ITERATIONS = 3000000;
+ private static final int TASK_COUNT = 10;
+ private static final long DELAY_AFTER_BENCH_MS = 1000;
+
+ private String mMethodName;
+
+ private final Bundle mTestResults = new Bundle();
+ private final ArrayList<Task> mTasks = new ArrayList<>();
+
+ // The member fields are used to ensure lambda capturing. They don't have the actual meaning.
+ private final Task mTask = new Task();
+ private final Rect mBounds = new Rect();
+ private int mTaskId;
+ private long mTime;
+ private boolean mTop;
+
+ @Rule
+ public final TestRule mRule = (base, description) -> new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ mMethodName = description.getMethodName();
+ mTasks.clear();
+ for (int i = 0; i < TASK_COUNT; i++) {
+ final Task t = new Task();
+ mTasks.add(t);
+ }
+ base.evaluate();
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, mTestResults);
+ }
+ };
+
+ @Test
+ public void test1ParamConsumer() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTask)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test2PrimitiveParamsConsumer() {
+ // Not in Integer#IntegerCache (-128~127) for autoboxing, that will create new object.
+ mTaskId = 12345;
+ mTime = 54321;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> forAllTask(t -> t.doSomething(mTaskId, mTime)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTaskId, mTime);
+ forAllTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void test3ParamsPredicate() {
+ mTop = true;
+ // In Integer#IntegerCache.
+ mTaskId = 10;
+
+ evaluate(LAMBDA_FORM_REGULAR, () -> handleTask(t -> t.doSomething(mBounds, mTop, mTaskId)));
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final PooledPredicate c = PooledLambda.obtainPredicate(Task::doSomething,
+ PooledLambda.__(Task.class), mBounds, mTop, mTaskId);
+ handleTask(c);
+ c.recycle();
+ });
+ }
+
+ @Test
+ public void testMessage() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Message m = Message.obtain().setCallback(() -> mTask.doSomething(mTaskId, mTime));
+ m.getCallback().run();
+ m.recycle();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Message m = PooledLambda.obtainMessage(Task::doSomething, mTask, mTaskId, mTime);
+ m.getCallback().run();
+ m.recycle();
+ });
+ }
+
+ @Test
+ public void testRunnable() {
+ evaluate(LAMBDA_FORM_REGULAR, () -> {
+ final Runnable r = mTask::doSomething;
+ r.run();
+ });
+ evaluate(LAMBDA_FORM_POOLED, () -> {
+ final Runnable r = PooledLambda.obtainRunnable(Task::doSomething, mTask).recycleOnUse();
+ r.run();
+ });
+ }
+
+ @Test
+ public void testMultiThread() {
+ final int numThread = 3;
+
+ final Runnable regularAction = () -> forAllTask(t -> t.doSomething(mTask));
+ final Runnable[] regularActions = new Runnable[numThread];
+ Arrays.fill(regularActions, regularAction);
+ evaluateMultiThread(LAMBDA_FORM_REGULAR, regularActions);
+
+ final Runnable pooledAction = () -> {
+ final PooledConsumer c = PooledLambda.obtainConsumer(Task::doSomething,
+ PooledLambda.__(Task.class), mTask);
+ forAllTask(c);
+ c.recycle();
+ };
+ final Runnable[] pooledActions = new Runnable[numThread];
+ Arrays.fill(pooledActions, pooledAction);
+ evaluateMultiThread(LAMBDA_FORM_POOLED, pooledActions);
+ }
+
+ private void forAllTask(Consumer<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ callback.accept(mTasks.get(i));
+ }
+ }
+
+ private void handleTask(Predicate<Task> callback) {
+ for (int i = mTasks.size() - 1; i >= 0; i--) {
+ final Task task = mTasks.get(i);
+ if (callback.test(task)) {
+ return;
+ }
+ }
+ }
+
+ private void evaluate(String title, Runnable action) {
+ for (int i = 0; i < WARMUP_ITERATIONS; i++) {
+ action.run();
+ }
+ performGc();
+
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateMultiThread(String title, Runnable[] actions) {
+ performGc();
+
+ final CountDownLatch latch = new CountDownLatch(actions.length);
+ final GcStatus startGcStatus = getGcStatus();
+ final long startTime = SystemClock.elapsedRealtime();
+ for (Runnable action : actions) {
+ new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ action.run();
+ }
+ latch.countDown();
+ };
+ }.start();
+ }
+ try {
+ latch.await();
+ } catch (InterruptedException ignored) {
+ }
+ evaluateResult(title, startGcStatus, startTime);
+ }
+
+ private void evaluateResult(String title, GcStatus startStatus, long startTime) {
+ final float elapsed = SystemClock.elapsedRealtime() - startTime;
+ // Sleep a while to see if GC may happen.
+ SystemClock.sleep(DELAY_AFTER_BENCH_MS);
+ final GcStatus endStatus = getGcStatus();
+ final GcInfo info = startStatus.calculateGcTime(endStatus, title, mTestResults);
+ Log.i(TAG, mMethodName + "_" + title + " execution time: "
+ + elapsed + "ms (avg=" + String.format("%.5f", elapsed / TEST_ITERATIONS) + "ms)"
+ + " GC time: " + String.format("%.3f", info.mTotalGcTime) + "ms"
+ + " GC paused time: " + String.format("%.3f", info.mTotalGcPausedTime) + "ms");
+ }
+
+ /** Cleans the test environment. */
+ private static void performGc() {
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ }
+
+ private static GcStatus getGcStatus() {
+ if (DEBUG) {
+ Log.i(TAG, "===== Read GC dump =====");
+ }
+ final GcStatus status = new GcStatus();
+ final List<String> vmDump = getVmDump();
+ Assume.assumeFalse("VM dump is empty", vmDump.isEmpty());
+ for (String line : vmDump) {
+ status.visit(line);
+ if (line.startsWith("DALVIK THREADS")) {
+ break;
+ }
+ }
+ return status;
+ }
+
+ private static List<String> getVmDump() {
+ final int myPid = Process.myPid();
+ // Another approach Debug#dumpJavaBacktraceToFileTimeout requires setenforce 0.
+ Process.sendSignal(myPid, Process.SIGNAL_QUIT);
+ // Give a chance to handle the signal.
+ SystemClock.sleep(100);
+
+ String dump = null;
+ final String pattern = myPid + " written to: ";
+ final List<String> logs = shell("logcat -v brief -d tombstoned:I *:S");
+ for (int i = logs.size() - 1; i >= 0; i--) {
+ final String log = logs.get(i);
+ // Log pattern: Traces for pid 9717 written to: /data/anr/trace_07
+ final int pos = log.indexOf(pattern);
+ if (pos > 0) {
+ dump = log.substring(pattern.length() + pos);
+ break;
+ }
+ }
+
+ Assume.assumeNotNull("Unable to find VM dump", dump);
+ // It requires system or root uid to read the trace.
+ return shell("cat " + dump);
+ }
+
+ private static List<String> shell(String command) {
+ final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ getInstrumentation().getUiAutomation().executeShellCommand(command));
+ final ArrayList<String> lines = new ArrayList<>();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ lines.add(line);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return lines;
+ }
+
+ /** An empty class which provides some methods with different type arguments. */
+ static class Task {
+ void doSomething() {
+ }
+
+ void doSomething(Task t) {
+ }
+
+ void doSomething(int taskId, long time) {
+ }
+
+ boolean doSomething(Rect bounds, boolean top, int taskId) {
+ return false;
+ }
+ }
+
+ static class ValPattern {
+ static final int TYPE_COUNT = 0;
+ static final int TYPE_TIME = 1;
+ static final String PATTERN_COUNT = "(\\d+)";
+ static final String PATTERN_TIME = "(\\d+\\.?\\d+)(\\w+)";
+ final String mRawPattern;
+ final Pattern mPattern;
+ final int mType;
+
+ int mIntValue;
+ float mFloatValue;
+
+ ValPattern(String p, int type) {
+ mRawPattern = p;
+ mPattern = Pattern.compile(
+ p + (type == TYPE_TIME ? PATTERN_TIME : PATTERN_COUNT) + ".*");
+ mType = type;
+ }
+
+ boolean visit(String line) {
+ final Matcher matcher = mPattern.matcher(line);
+ if (!matcher.matches()) {
+ return false;
+ }
+ final String value = matcher.group(1);
+ if (value == null) {
+ return false;
+ }
+ if (mType == TYPE_COUNT) {
+ mIntValue = Integer.parseInt(value);
+ return true;
+ }
+ final float time = Float.parseFloat(value);
+ final String unit = matcher.group(2);
+ if (unit == null) {
+ return false;
+ }
+ // Refer to art/libartbase/base/time_utils.cc
+ switch (unit) {
+ case "s":
+ mFloatValue = time * 1000;
+ break;
+ case "ms":
+ mFloatValue = time;
+ break;
+ case "us":
+ mFloatValue = time / 1000;
+ break;
+ case "ns":
+ mFloatValue = time / 1000 / 1000;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return mRawPattern + (mType == TYPE_TIME ? (mFloatValue + "ms") : mIntValue);
+ }
+ }
+
+ /** Parses the dump pattern of Heap::DumpGcPerformanceInfo. */
+ private static class GcStatus {
+ private static final int TOTAL_GC_TIME_INDEX = 1;
+ private static final int TOTAL_GC_PAUSED_TIME_INDEX = 5;
+
+ // Refer to art/runtime/gc/heap.cc
+ final ValPattern[] mPatterns = {
+ new ValPattern("Total GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total time waiting for GC to complete: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total blocking GC count: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Total blocking GC time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total mutator paused time: ", ValPattern.TYPE_TIME),
+ new ValPattern("Total number of allocations ", ValPattern.TYPE_COUNT),
+ new ValPattern("concurrent copying paused: Sum: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying total time: ", ValPattern.TYPE_TIME),
+ new ValPattern("concurrent copying freed: ", ValPattern.TYPE_COUNT),
+ new ValPattern("Peak regions allocated ", ValPattern.TYPE_COUNT),
+ };
+
+ void visit(String dumpLine) {
+ for (ValPattern p : mPatterns) {
+ if (p.visit(dumpLine)) {
+ if (DEBUG) {
+ Log.i(TAG, " " + p);
+ }
+ }
+ }
+ }
+
+ GcInfo calculateGcTime(GcStatus newStatus, String title, Bundle result) {
+ Log.i(TAG, "===== GC status of " + title + " =====");
+ final GcInfo info = new GcInfo();
+ for (int i = 0; i < mPatterns.length; i++) {
+ final ValPattern p = mPatterns[i];
+ if (p.mType == ValPattern.TYPE_COUNT) {
+ final int diff = newStatus.mPatterns[i].mIntValue - p.mIntValue;
+ Log.i(TAG, " " + p.mRawPattern + diff);
+ if (diff > 0) {
+ result.putInt("[" + title + "] " + p.mRawPattern, diff);
+ }
+ continue;
+ }
+ final float diff = newStatus.mPatterns[i].mFloatValue - p.mFloatValue;
+ Log.i(TAG, " " + p.mRawPattern + diff + "ms");
+ if (diff > 0) {
+ result.putFloat("[" + title + "] " + p.mRawPattern + "(ms)", diff);
+ }
+ if (i == TOTAL_GC_TIME_INDEX) {
+ info.mTotalGcTime = diff;
+ } else if (i == TOTAL_GC_PAUSED_TIME_INDEX) {
+ info.mTotalGcPausedTime = diff;
+ }
+ }
+ return info;
+ }
+ }
+
+ private static class GcInfo {
+ float mTotalGcTime;
+ float mTotalGcPausedTime;
+ }
+}
diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt
index 5dd0fda4da28..9ba56e44fe88 100644
--- a/tests/net/java/android/net/NetworkTemplateTest.kt
+++ b/tests/net/java/android/net/NetworkTemplateTest.kt
@@ -26,6 +26,7 @@ import android.net.NetworkStats.METERED_ALL
import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_WIFI
+import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.buildTemplateMobileWithRatType
import android.telephony.TelephonyManager
@@ -145,11 +146,13 @@ class NetworkTemplateTest {
assertParcelSane(templateWifi, 8)
}
- // Verify NETWORK_TYPE_ALL does not conflict with TelephonyManager#NETWORK_TYPE_* constants.
+ // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
+ // TelephonyManager#NETWORK_TYPE_* constants.
@Test
- fun testNetworkTypeAll() {
+ fun testNetworkTypeConstants() {
for (ratType in TelephonyManager.getAllNetworkTypes()) {
assertNotEquals(NETWORK_TYPE_ALL, ratType)
+ assertNotEquals(NETWORK_TYPE_5G_NSA, ratType)
}
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 16fed39bcc74..6dc4fced19a2 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -17,6 +17,7 @@
package com.android.server.net;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -30,7 +31,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
+import android.net.NetworkTemplate;
import android.os.test.TestLooper;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -61,7 +64,6 @@ public final class NetworkStatsSubscriptionsMonitorTest {
private static final String TEST_IMSI3 = "466929999999999";
@Mock private Context mContext;
- @Mock private PhoneStateListener mPhoneStateListener;
@Mock private SubscriptionManager mSubscriptionManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private NetworkStatsSubscriptionsMonitor.Delegate mDelegate;
@@ -215,4 +217,55 @@ public final class NetworkStatsSubscriptionsMonitorTest {
verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
}
+
+
+ @Test
+ public void test5g() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type. Also capture listener for later use.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ final RatTypeListener listener = CollectionUtils
+ .find(ratTypeListenerCaptor.getAllValues(), it -> it.getSubId() == TEST_SUBID1);
+ assertNotNull(listener);
+
+ // Set RAT type to 5G NSA (non-standalone) mode, verify the monitor outputs
+ // NETWORK_TYPE_5G_NSA.
+ final ServiceState serviceState = mock(ServiceState.class);
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, NetworkTemplate.NETWORK_TYPE_5G_NSA);
+ reset(mDelegate);
+
+ // Set RAT type to LTE without NR connected, the RAT type should be downgraded to LTE.
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
+ reset(mDelegate);
+
+ // Verify NR connected with other RAT type does not take effect.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_UMTS);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+
+ // Set RAT type to 5G standalone mode, the RAT type should be NR.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_NR);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ reset(mDelegate);
+
+ // Set NR state to none in standalone mode does not change anything.
+ when(serviceState.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_NR);
+ when(serviceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_NONE);
+ listener.onServiceStateChanged(serviceState);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_NR);
+ }
}
diff --git a/tools/processors/intdef_mappings/Android.bp b/tools/processors/intdef_mappings/Android.bp
new file mode 100644
index 000000000000..e255f7c784d3
--- /dev/null
+++ b/tools/processors/intdef_mappings/Android.bp
@@ -0,0 +1,33 @@
+java_plugin {
+ name: "intdef-annotation-processor",
+
+ processor_class: "android.processor.IntDefProcessor",
+
+ srcs: [
+ ":framework-annotations",
+ "src/**/*.java",
+ "src/**/*.kt"
+ ],
+
+ use_tools_jar: true,
+}
+
+java_test_host {
+ name: "intdef-annotation-processor-test",
+
+ srcs: [
+ "test/**/*.java",
+ "test/**/*.kt"
+ ],
+ java_resource_dirs: ["test/resources"],
+
+ static_libs: [
+ "compile-testing-prebuilt",
+ "truth-prebuilt",
+ "junit",
+ "guava",
+ "intdef-annotation-processor"
+ ],
+
+ test_suites: ["general-tests"],
+} \ No newline at end of file
diff --git a/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
new file mode 100644
index 000000000000..84faeea36eea
--- /dev/null
+++ b/tools/processors/intdef_mappings/src/android/processor/IntDefProcessor.kt
@@ -0,0 +1,190 @@
+/*
+ * 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.processor
+
+import android.annotation.IntDef
+import com.sun.source.tree.IdentifierTree
+import com.sun.source.tree.MemberSelectTree
+import com.sun.source.tree.NewArrayTree
+import com.sun.source.util.SimpleTreeVisitor
+import com.sun.source.util.Trees
+import java.io.IOException
+import java.io.Writer
+import javax.annotation.processing.AbstractProcessor
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.SourceVersion
+import javax.lang.model.element.AnnotationValue
+import javax.lang.model.element.TypeElement
+import javax.tools.Diagnostic.Kind
+import javax.tools.StandardLocation.CLASS_OUTPUT
+import kotlin.collections.set
+
+
+/**
+ * The IntDefProcessor is intended to generate a mapping from ints to their respective string
+ * identifier for each IntDef for use by Winscope or any other tool which requires such a mapping.
+ *
+ * The processor will run when building :frameworks-all and dump all the IntDef mappings found the
+ * files the make up :frameworks-all as json to outputPath.
+ */
+class IntDefProcessor : AbstractProcessor() {
+ private val outputName = "intDefMapping.json"
+
+ override fun getSupportedSourceVersion(): SourceVersion = SourceVersion.latest()
+
+ // Define what the annotation we care about are for compiler optimization
+ override fun getSupportedAnnotationTypes() = LinkedHashSet<String>().apply {
+ add(IntDef::class.java.name)
+ }
+
+ override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
+ // There should only be one matching annotation definition for intDef
+ val annotationType = annotations.firstOrNull() ?: return false
+ val annotatedElements = roundEnv.getElementsAnnotatedWith(annotationType)
+
+ val annotationTypeToIntDefMapping = annotatedElements.associate { annotatedElement ->
+ val type = (annotatedElement as TypeElement).qualifiedName.toString()
+ val mapping = generateIntDefMapping(annotatedElement, annotationType)
+ val intDef = annotatedElement.getAnnotation(IntDef::class.java)
+ type to IntDefMapping(mapping, intDef.flag)
+ }
+
+ try {
+ outputToFile(annotationTypeToIntDefMapping)
+ } catch (e: IOException) {
+ error("Failed to write IntDef mappings :: $e")
+ }
+ return false
+ }
+
+ private fun generateIntDefMapping(
+ annotatedElement: TypeElement,
+ annotationType: TypeElement
+ ): Map<Int, String> {
+ // LinkedHashMap makes sure ordering is the same as in the code
+ val mapping = LinkedHashMap<Int, String>()
+
+ val annotationMirror = annotatedElement.annotationMirrors
+ // Should only ever be one matching this condition
+ .first { it.annotationType.asElement() == annotationType }
+
+ val value = annotationMirror.elementValues.entries
+ .first { entry -> entry.key.simpleName.contentEquals("value") }
+ .value
+
+ val trees = Trees.instance(processingEnv)
+ val tree = trees.getTree(annotatedElement, annotationMirror, value)
+
+ val identifiers = ArrayList<String>()
+ tree.accept(IdentifierVisitor(), identifiers)
+
+ val values = value.value as List<AnnotationValue>
+
+ for (i in identifiers.indices) {
+ mapping[values[i].value as Int] = identifiers[i]
+ }
+
+ return mapping
+ }
+
+ private class IdentifierVisitor : SimpleTreeVisitor<Void, ArrayList<String>>() {
+ override fun visitNewArray(node: NewArrayTree, indentifiers: ArrayList<String>): Void? {
+ for (initializer in node.initializers) {
+ initializer.accept(this, indentifiers)
+ }
+
+ return null
+ }
+
+ override fun visitMemberSelect(node: MemberSelectTree, indentifiers: ArrayList<String>):
+ Void? {
+ indentifiers.add(node.identifier.toString())
+
+ return null
+ }
+
+ override fun visitIdentifier(node: IdentifierTree, indentifiers: ArrayList<String>): Void? {
+ indentifiers.add(node.name.toString())
+
+ return null
+ }
+ }
+
+ @Throws(IOException::class)
+ private fun outputToFile(annotationTypeToIntDefMapping: Map<String, IntDefMapping>) {
+ val resource = processingEnv.filer.createResource(
+ CLASS_OUTPUT, "com.android.winscope", outputName)
+ val writer = resource.openWriter()
+ serializeTo(annotationTypeToIntDefMapping, writer)
+ writer.close()
+ }
+
+ private fun error(message: String) {
+ processingEnv.messager.printMessage(Kind.ERROR, message)
+ }
+
+ private fun note(message: String) {
+ processingEnv.messager.printMessage(Kind.NOTE, message)
+ }
+
+ class IntDefMapping(val mapping: Map<Int, String>, val flag: Boolean) {
+ val size
+ get() = this.mapping.size
+
+ val entries
+ get() = this.mapping.entries
+ }
+
+ companion object {
+ fun serializeTo(
+ annotationTypeToIntDefMapping: Map<String, IntDefMapping>,
+ writer: Writer
+ ) {
+ val indent = " "
+
+ writer.appendln("{")
+
+ val intDefTypesCount = annotationTypeToIntDefMapping.size
+ var currentIntDefTypesCount = 0
+ for ((field, intDefMapping) in annotationTypeToIntDefMapping) {
+ writer.appendln("""$indent"$field": {""")
+
+ // Start IntDef
+
+ writer.appendln("""$indent$indent"flag": ${intDefMapping.flag},""")
+
+ writer.appendln("""$indent$indent"values": {""")
+ intDefMapping.entries.joinTo(writer, separator = ",\n") { (value, identifier) ->
+ """$indent$indent$indent"$value": "$identifier""""
+ }
+ writer.appendln()
+ writer.appendln("$indent$indent}")
+
+ // End IntDef
+
+ writer.append("$indent}")
+ if (++currentIntDefTypesCount < intDefTypesCount) {
+ writer.appendln(",")
+ } else {
+ writer.appendln("")
+ }
+ }
+
+ writer.appendln("}")
+ }
+ }
+}
diff --git a/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt
new file mode 100644
index 000000000000..c0c159c98aac
--- /dev/null
+++ b/tools/processors/intdef_mappings/test/android/processor/IntDefProcessorTest.kt
@@ -0,0 +1,162 @@
+/*
+ * 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.processor
+
+import android.processor.IntDefProcessor.IntDefMapping
+import com.google.common.collect.ObjectArrays.concat
+import com.google.testing.compile.CompilationSubject.assertThat
+import com.google.testing.compile.Compiler.javac
+import com.google.testing.compile.JavaFileObjects
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import java.io.StringWriter
+import javax.tools.JavaFileObject
+import javax.tools.StandardLocation.CLASS_OUTPUT
+
+/**
+ * Tests for [IntDefProcessor]
+ */
+class IntDefProcessorTest {
+ private val mAnnotations = arrayOf<JavaFileObject>(
+ JavaFileObjects.forSourceLines("android.annotation.IntDef",
+ "package android.annotation;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.Target;",
+ "import static java.lang.annotation.ElementType.ANNOTATION_TYPE;",
+ "import static java.lang.annotation.RetentionPolicy.SOURCE;",
+ "@Retention(SOURCE)",
+ "@Target({ANNOTATION_TYPE})",
+ "public @interface IntDef {",
+ " String[] prefix() default {};",
+ " String[] suffix() default {};",
+ " int[] value() default {};",
+ " boolean flag() default false;",
+ "}")
+ )
+
+ @Test
+ public fun annotationProcessorGeneratesMapping() {
+ val sources: Array<JavaFileObject> = arrayOf(
+ JavaFileObjects.forSourceLines(
+ "com.android.server.accessibility.magnification.MagnificationGestureMatcher",
+ "package com.android.server.accessibility.magnification;",
+ "import android.annotation.IntDef;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.RetentionPolicy;",
+ "class MagnificationGestureMatcher {",
+ " private static final int GESTURE_BASE = 100;",
+ " public static final int GESTURE_TWO_FINGER_DOWN = GESTURE_BASE + 1;",
+ " public static final int GESTURE_SWIPE = GESTURE_BASE + 2;",
+ " @IntDef(prefix = {\"GESTURE_MAGNIFICATION_\"}, value = {",
+ " GESTURE_TWO_FINGER_DOWN,",
+ " GESTURE_SWIPE",
+ " })",
+ " @Retention(RetentionPolicy.SOURCE)",
+ " @interface GestureId {}",
+ "}"
+ ),
+ JavaFileObjects.forSourceLines(
+ "android.service.storage.ExternalStorageService",
+ "package android.service.storage;",
+ "import android.annotation.IntDef;",
+ "import java.lang.annotation.Retention;",
+ "import java.lang.annotation.RetentionPolicy;",
+ "class MagnificationGestureMatcher {",
+ " public static final int FLAG_SESSION_TYPE_FUSE = 1 << 0;",
+ " public static final int FLAG_SESSION_ATTRIBUTE_INDEXABLE = 1 << 1;",
+ " @IntDef(flag = true, prefix = {\"FLAG_SESSION_\"},",
+ " value = {FLAG_SESSION_TYPE_FUSE, FLAG_SESSION_ATTRIBUTE_INDEXABLE})",
+ " @Retention(RetentionPolicy.SOURCE)",
+ " public @interface SessionFlag {}",
+ "}"
+ )
+ )
+
+ val expectedFile = """
+ {
+ "com.android.server.accessibility.magnification.MagnificationGestureMatcher.GestureId": {
+ "flag": false,
+ "values": {
+ "101": "GESTURE_TWO_FINGER_DOWN",
+ "102": "GESTURE_SWIPE"
+ }
+ },
+ "android.service.storage.MagnificationGestureMatcher.SessionFlag": {
+ "flag": true,
+ "values": {
+ "1": "FLAG_SESSION_TYPE_FUSE",
+ "2": "FLAG_SESSION_ATTRIBUTE_INDEXABLE"
+ }
+ }
+ }
+
+ """.trimIndent()
+
+ val filesToCompile = concat(mAnnotations, sources, JavaFileObject::class.java)
+
+ val compilation = javac()
+ .withProcessors(IntDefProcessor())
+ .compile(filesToCompile.toMutableList())
+
+ assertThat(compilation).succeeded()
+ assertThat(compilation).generatedFile(CLASS_OUTPUT, "com.android.winscope",
+ "intDefMapping.json").contentsAsUtf8String().isEqualTo(expectedFile)
+ }
+
+ @Test
+ public fun serializesMappingCorrectly() {
+ val map = linkedMapOf(
+ "SimpleIntDef" to IntDefMapping(linkedMapOf(
+ 0x0001 to "VAL_1",
+ 0x0002 to "VAL_2",
+ 0x0003 to "VAL_3"
+ ), flag = false),
+ "Flags" to IntDefMapping(linkedMapOf(
+ 0b0001 to "PRIVATE_FLAG_1",
+ 0b0010 to "PRIVATE_FLAG_2",
+ 0b0100 to "PRIVATE_FLAG_3"
+ ), flag = true)
+ )
+
+ val writer = StringWriter()
+ IntDefProcessor.serializeTo(map, writer)
+
+ val actualOutput = writer.toString()
+ val expectedOutput = """
+ {
+ "SimpleIntDef": {
+ "flag": false,
+ "values": {
+ "1": "VAL_1",
+ "2": "VAL_2",
+ "3": "VAL_3"
+ }
+ },
+ "Flags": {
+ "flag": true,
+ "values": {
+ "1": "PRIVATE_FLAG_1",
+ "2": "PRIVATE_FLAG_2",
+ "4": "PRIVATE_FLAG_3"
+ }
+ }
+ }
+
+ """.trimIndent()
+
+ assertEquals(actualOutput, expectedOutput)
+ }
+} \ No newline at end of file
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index e3b6db08c503..43387fc054b5 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -121,10 +121,26 @@ cc_library {
],
target: {
android: {
- shared_libs: ["libstatssocket"],
+ shared_libs: [
+ "libstatssocket",
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
host: {
- static_libs: ["libstatssocket"],
+ static_libs: [
+ "libstatssocket",
+ "libstatspull",
+ "statsd-aidl-ndk_platform",
+ ],
+ shared_libs: ["libbinder_ndk"],
+ export_static_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
},
}
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 0c6c0099e459..21e88b360dcd 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -82,21 +82,77 @@ static void write_annotations(FILE* out, int argIndex,
}
}
-static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
+static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
+ const AtomDecl& attributionDecl) {
+ int argIndex = 1;
+ fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ fprintf(out,
+ " AStatsEvent_writeAttributionChain(event, "
+ "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
+ "static_cast<uint8_t>(%s_length));\n",
+ uidName, tagName, uidName);
+ break;
+ }
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ " AStatsEvent_writeByteArray(event, "
+ "reinterpret_cast<const uint8_t*>(arg%d.arg), "
+ "arg%d.arg_length);\n",
+ argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ argIndex++;
+ }
+ return 0;
+}
+
+static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
fprintf(out, "\n");
- for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
// Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
+ write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
- int argIndex = 1;
+ // Write method body.
if (supportQ) {
+ int argIndex = 1;
fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\n");
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
@@ -138,78 +194,36 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "");
argIndex++;
}
- fprintf(out, " return event.writeToSocket();\n");
+ fprintf(out, " return event.writeToSocket();\n"); // end method body.
} else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
- fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out,
- " AStatsEvent_writeAttributionChain(event, "
- "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
- "static_cast<uint8_t>(%s_length));\n",
- uidName, tagName, uidName);
- break;
- }
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- " AStatsEvent_writeByteArray(event, "
- "reinterpret_cast<const uint8_t*>(arg%d.arg), "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- break;
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_INT: // Fall through.
- case JAVA_TYPE_ENUM:
- fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- argIndex++;
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
}
fprintf(out, " const int ret = AStatsEvent_write(event);\n");
fprintf(out, " AStatsEvent_release(event);\n");
- fprintf(out, " return ret;\n");
+ fprintf(out, " return ret;\n"); // end method body.
}
- fprintf(out, "}\n\n");
+ fprintf(out, "}\n\n"); // end method.
}
return 0;
}
-static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
+static void write_native_stats_write_non_chained_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
fprintf(out, "\n");
- for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
- signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
+ for (auto signature_it = signatureInfoMap.begin();
+ signature_it != signatureInfoMap.end(); signature_it++) {
vector<java_type_t> signature = signature_it->first;
// Key value pairs not supported in native.
if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write_non_chained", signature,
+ write_native_method_signature(out, "int stats_write_non_chained(", signature,
attributionDecl, " {");
vector<java_type_t> newSignature;
@@ -235,6 +249,34 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
}
}
+static int write_native_build_stats_event_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
+ fprintf(out, "\n");
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ vector<java_type_t> signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ // Key value pairs not supported in native.
+ if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ continue;
+ }
+ write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ signature, attributionDecl, " {");
+
+ fprintf(out, " AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
+ }
+ fprintf(out, " AStatsEvent_build(event);\n"); // end method body.
+
+ fprintf(out, "}\n\n"); // end method.
+ }
+ return 0;
+}
+
static void write_native_method_header(FILE* out, const string& methodName,
const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
@@ -262,13 +304,22 @@ int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributi
fprintf(out, "#include <StatsEventCompat.h>\n");
} else {
fprintf(out, "#include <stats_event.h>\n");
+
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
}
+
+
fprintf(out, "\n");
write_namespace(out, cppNamespace);
- write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
- write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
+ write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ attributionDecl);
// Print footer
fprintf(out, "\n");
@@ -288,6 +339,9 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attrib
fprintf(out, "#include <vector>\n");
fprintf(out, "#include <map>\n");
fprintf(out, "#include <set>\n");
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
fprintf(out, "\n");
write_namespace(out, cppNamespace);
@@ -337,12 +391,22 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attrib
fprintf(out, "//\n");
fprintf(out, "// Write methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
+ write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
+ fprintf(out, "\n");
fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
+ write_native_method_header(out, "int stats_write_non_chained(", atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ fprintf(out, "\n");
+
+ // Print pulled atoms methods.
+ fprintf(out, "//\n");
+ fprintf(out, "// Add AStatsEvent methods\n");
+ fprintf(out, "//\n");
+ write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ atoms.pulledAtomsSignatureInfoMap,
attributionDecl);
fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index abb89133e58e..4b3734053421 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -182,10 +182,10 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
fprintf(out, "\n");
}
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer) {
- fprintf(out, "%s(int32_t code", methodName.c_str());
+ fprintf(out, "%sint32_t code", signaturePrefix.c_str());
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index 73e0cb838227..42dc90eb79dc 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -59,7 +59,7 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces);
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer);
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 819e75ba1fed..61ce44c3b5b9 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -20,6 +20,7 @@ cc_binary_host {
"libutils",
"libcutils",
"liblog",
+ "libui-types",
],
// This tool is prebuilt if we're doing an app-only build.
diff --git a/wifi/TEST_MAPPING b/wifi/TEST_MAPPING
new file mode 100644
index 000000000000..fde3a6aa993c
--- /dev/null
+++ b/wifi/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWifiTestCases",
+ "options": [
+ {
+ "exclude-annotation": "android.net.wifi.cts.VirtualDeviceNotSupported"
+ }
+ ]
+ }
+ ]
+}