summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java27
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java5
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResults.java5
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl25
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java11
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java2
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java155
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java143
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java11
-rw-r--r--apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java126
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java125
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java8
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java14
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java42
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java189
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java27
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java72
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java15
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java11
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotDisplayedBySystemMap.java (renamed from apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java)6
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java28
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java (renamed from apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java)143
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesDocument.java (renamed from apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleDocument.java)14
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesMap.java (renamed from apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java)4
-rw-r--r--apex/appsearch/synced_jetpack_changeid.txt2
-rw-r--r--apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java207
-rw-r--r--api/Android.bp73
-rwxr-xr-xapi/api_versions_trimmer.py136
-rw-r--r--api/api_versions_trimmer_unittests.py307
-rw-r--r--core/java/android/app/AppOpsManager.java50
-rw-r--r--core/java/android/app/LoadedApk.java4
-rw-r--r--core/java/android/app/Notification.java14
-rw-r--r--core/java/android/app/WallpaperColors.java23
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl2
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java2
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java7
-rw-r--r--core/java/android/content/pm/IPackageInstaller.aidl2
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl5
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java6
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java63
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedComponent.java2
-rw-r--r--core/java/android/hardware/Sensor.java12
-rw-r--r--core/java/android/hardware/SensorManager.java7
-rw-r--r--core/java/android/hardware/biometrics/BiometricFingerprintConstants.java11
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java4
-rw-r--r--core/java/android/hardware/display/DisplayManagerInternal.java47
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java3
-rw-r--r--core/java/android/hardware/input/InputDeviceVibrator.java8
-rw-r--r--core/java/android/net/VpnManager.java4
-rw-r--r--core/java/android/net/vcn/VcnGatewayConnectionConfig.java2
-rw-r--r--core/java/android/os/SystemVibrator.java27
-rw-r--r--core/java/android/os/Vibrator.java31
-rw-r--r--core/java/android/os/VibratorInfo.java275
-rw-r--r--core/java/android/permission/PermissionManager.java35
-rw-r--r--core/java/android/permission/PermissionUsageHelper.java4
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java1
-rw-r--r--core/java/android/service/contentcapture/ActivityEvent.java20
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java10
-rw-r--r--core/java/android/service/voice/HotwordDetectedResult.java71
-rw-r--r--core/java/android/service/voice/HotwordDetectionService.java13
-rw-r--r--core/java/android/service/voice/SoftwareHotwordDetector.java34
-rw-r--r--core/java/android/view/CrossWindowBlurListeners.java6
-rw-r--r--core/java/android/view/InsetsController.java2
-rw-r--r--core/java/android/view/ScrollCaptureTarget.java27
-rw-r--r--core/java/android/view/SurfaceControl.java29
-rw-r--r--core/java/android/view/SurfaceView.java23
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/view/ViewRootInsetsControllerHost.java4
-rw-r--r--core/java/android/view/WindowInsetsAnimation.java7
-rw-r--r--core/java/android/view/contentcapture/ContentCaptureEvent.java9
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java5
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java13
-rw-r--r--core/java/android/view/translation/UiTranslationController.java2
-rw-r--r--core/java/android/widget/TextView.java45
-rw-r--r--core/java/android/widget/TextViewTranslationCallback.java69
-rw-r--r--core/java/android/window/SplashScreenView.java1
-rw-r--r--core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl3
-rw-r--r--core/java/com/android/internal/infra/ServiceConnector.java2
-rw-r--r--core/java/com/android/internal/os/AppZygoteInit.java2
-rw-r--r--core/java/com/android/internal/os/BatterySipper.java3
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java3
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java18
-rw-r--r--core/java/com/android/internal/os/Zygote.java30
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java3
-rw-r--r--core/java/com/android/internal/util/function/DodecConsumer.java29
-rw-r--r--core/java/com/android/internal/util/function/DodecFunction.java28
-rw-r--r--core/java/com/android/internal/util/function/DodecPredicate.java28
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambda.java229
-rwxr-xr-xcore/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java30
-rw-r--r--core/java/com/android/internal/view/ScrollCaptureViewSupport.java15
-rw-r--r--core/java/com/android/internal/widget/CachingIconView.java6
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java6
-rw-r--r--core/java/com/android/internal/widget/LockPatternView.java5
-rw-r--r--core/java/com/android/server/AppWidgetBackupBridge.java8
-rw-r--r--core/java/com/android/server/SystemConfig.java29
-rw-r--r--core/java/com/android/server/WidgetBackupProvider.java4
-rw-r--r--core/jni/android_view_SurfaceControl.cpp12
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp58
-rw-r--r--core/jni/fd_utils.cpp72
-rw-r--r--core/jni/fd_utils.h13
-rw-r--r--core/proto/android/server/apphibernationservice.proto1
-rw-r--r--core/res/res/layout/splash_screen_view.xml5
-rw-r--r--core/res/res/values-af/strings.xml2
-rw-r--r--core/res/res/values-am/strings.xml3
-rw-r--r--core/res/res/values-ar/strings.xml3
-rw-r--r--core/res/res/values-as/strings.xml3
-rw-r--r--core/res/res/values-az/strings.xml15
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml2
-rw-r--r--core/res/res/values-be/strings.xml3
-rw-r--r--core/res/res/values-bg/strings.xml3
-rw-r--r--core/res/res/values-bn/strings.xml10
-rw-r--r--core/res/res/values-bs/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml3
-rw-r--r--core/res/res/values-cs/strings.xml5
-rw-r--r--core/res/res/values-da/strings.xml3
-rw-r--r--core/res/res/values-de/strings.xml4
-rw-r--r--core/res/res/values-el/strings.xml3
-rw-r--r--core/res/res/values-en-rAU/strings.xml2
-rw-r--r--core/res/res/values-en-rCA/strings.xml2
-rw-r--r--core/res/res/values-en-rGB/strings.xml2
-rw-r--r--core/res/res/values-en-rIN/strings.xml2
-rw-r--r--core/res/res/values-en-rXC/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml2
-rw-r--r--core/res/res/values-es/strings.xml3
-rw-r--r--core/res/res/values-et/strings.xml5
-rw-r--r--core/res/res/values-eu/strings.xml7
-rw-r--r--core/res/res/values-fa/strings.xml21
-rw-r--r--core/res/res/values-fi/strings.xml3
-rw-r--r--core/res/res/values-fr-rCA/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml3
-rw-r--r--core/res/res/values-gl/strings.xml3
-rw-r--r--core/res/res/values-gu/strings.xml10
-rw-r--r--core/res/res/values-hi/strings.xml3
-rw-r--r--core/res/res/values-hr/strings.xml2
-rw-r--r--core/res/res/values-hu/strings.xml3
-rw-r--r--core/res/res/values-hy/strings.xml2
-rw-r--r--core/res/res/values-in/strings.xml3
-rw-r--r--core/res/res/values-is/strings.xml3
-rw-r--r--core/res/res/values-it/strings.xml2
-rw-r--r--core/res/res/values-iw/strings.xml3
-rw-r--r--core/res/res/values-ja/strings.xml3
-rw-r--r--core/res/res/values-ka/strings.xml3
-rw-r--r--core/res/res/values-kk/strings.xml3
-rw-r--r--core/res/res/values-km/strings.xml3
-rw-r--r--core/res/res/values-kn/strings.xml3
-rw-r--r--core/res/res/values-ko/strings.xml3
-rw-r--r--core/res/res/values-ky/strings.xml3
-rw-r--r--core/res/res/values-lo/strings.xml2
-rw-r--r--core/res/res/values-lt/strings.xml3
-rw-r--r--core/res/res/values-lv/strings.xml3
-rw-r--r--core/res/res/values-mk/strings.xml3
-rw-r--r--core/res/res/values-ml/strings.xml3
-rw-r--r--core/res/res/values-mn/strings.xml3
-rw-r--r--core/res/res/values-mr/strings.xml6
-rw-r--r--core/res/res/values-ms/strings.xml3
-rw-r--r--core/res/res/values-my/strings.xml3
-rw-r--r--core/res/res/values-nb/strings.xml3
-rw-r--r--core/res/res/values-ne/strings.xml10
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-or/strings.xml4
-rw-r--r--core/res/res/values-pa/strings.xml4
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-pt-rBR/strings.xml2
-rw-r--r--core/res/res/values-pt-rPT/strings.xml2
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values-ro/strings.xml5
-rw-r--r--core/res/res/values-ru/strings.xml3
-rw-r--r--core/res/res/values-si/strings.xml3
-rw-r--r--core/res/res/values-sk/strings.xml3
-rw-r--r--core/res/res/values-sl/strings.xml3
-rw-r--r--core/res/res/values-sq/strings.xml3
-rw-r--r--core/res/res/values-sr/strings.xml2
-rw-r--r--core/res/res/values-sv/strings.xml3
-rw-r--r--core/res/res/values-sw/strings.xml2
-rw-r--r--core/res/res/values-ta/strings.xml3
-rw-r--r--core/res/res/values-te/strings.xml10
-rw-r--r--core/res/res/values-television/config.xml4
-rw-r--r--core/res/res/values-th/strings.xml3
-rw-r--r--core/res/res/values-tl/strings.xml3
-rw-r--r--core/res/res/values-tr/strings.xml2
-rw-r--r--core/res/res/values-uk/strings.xml2
-rw-r--r--core/res/res/values-ur/strings.xml3
-rw-r--r--core/res/res/values-uz/strings.xml3
-rw-r--r--core/res/res/values-vi/strings.xml3
-rw-r--r--core/res/res/values-zh-rCN/strings.xml3
-rw-r--r--core/res/res/values-zh-rHK/strings.xml3
-rw-r--r--core/res/res/values-zh-rTW/strings.xml3
-rw-r--r--core/res/res/values-zu/strings.xml3
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java4
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java44
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java89
-rw-r--r--core/tests/coretests/src/android/os/VibratorInfoTest.java63
-rw-r--r--core/tests/coretests/src/android/os/VibratorTest.java119
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java2
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java31
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java1
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java13
-rw-r--r--libs/hwui/RenderNode.h2
-rw-r--r--libs/hwui/effects/StretchEffect.cpp7
-rw-r--r--libs/hwui/effects/StretchEffect.h4
-rw-r--r--location/java/android/location/GnssMeasurement.java22
-rw-r--r--location/java/android/location/ILocationManager.aidl3
-rw-r--r--location/java/android/location/LastLocationRequest.java60
-rw-r--r--location/java/android/location/LocationManager.java63
-rw-r--r--location/java/android/location/LocationRequest.java72
-rw-r--r--location/java/android/location/provider/ProviderRequest.java53
-rwxr-xr-xmedia/java/android/mtp/MtpDatabase.java37
-rw-r--r--media/java/android/mtp/MtpDevice.java13
-rw-r--r--media/java/android/mtp/MtpDeviceInfo.java27
-rw-r--r--media/jni/android_mtp_MtpDatabase.cpp2
-rw-r--r--media/jni/android_mtp_MtpDevice.cpp61
-rw-r--r--obex/javax/obex/ObexHelper.java14
-rw-r--r--obex/javax/obex/ObexTransport.java2
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml21
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml21
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml4
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml1
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java80
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java80
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java96
-rw-r--r--packages/SettingsLib/FooterPreference/res/values-bn/strings.xml21
-rw-r--r--packages/SettingsLib/FooterPreference/res/values-de/strings.xml21
-rw-r--r--packages/SettingsLib/FooterPreference/res/values-mr/strings.xml21
-rw-r--r--packages/SettingsLib/FooterPreference/res/values-ne/strings.xml21
-rw-r--r--packages/SettingsLib/FooterPreference/res/values-or/strings.xml21
-rw-r--r--packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java33
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml1
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml3
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java20
-rw-r--r--packages/SystemUI/AndroidManifest.xml8
-rw-r--r--packages/SystemUI/res-keyguard/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res-product/values-fa/strings.xml4
-rw-r--r--packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml52
-rw-r--r--packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml23
-rw-r--r--packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml23
-rw-r--r--packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml41
-rw-r--r--packages/SystemUI/res/anim/tv_privacy_chip_expand.xml41
-rw-r--r--packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml25
-rw-r--r--packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml29
-rw-r--r--packages/SystemUI/res/color/bottom_sheet_button_background_color.xml21
-rw-r--r--packages/SystemUI/res/color/bottom_sheet_button_text_color.xml21
-rw-r--r--packages/SystemUI/res/drawable/bottom_sheet_background.xml (renamed from packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml)13
-rw-r--r--packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml20
-rw-r--r--packages/SystemUI/res/drawable/bottom_sheet_button_background.xml20
-rw-r--r--packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml22
-rw-r--r--packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml22
-rw-r--r--packages/SystemUI/res/layout/media_output_list_item.xml1
-rw-r--r--packages/SystemUI/res/layout/tv_bottom_sheet.xml87
-rw-r--r--packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml25
-rw-r--r--packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml20
-rw-r--r--packages/SystemUI/res/transition/tv_privacy_chip_expand.xml20
-rw-r--r--packages/SystemUI/res/values-am/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml6
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-be/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml9
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml6
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-da/strings.xml6
-rw-r--r--packages/SystemUI/res/values-de/strings.xml9
-rw-r--r--packages/SystemUI/res/values-el/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es/strings.xml6
-rw-r--r--packages/SystemUI/res/values-et/strings.xml6
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml3
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml6
-rw-r--r--packages/SystemUI/res/values-in/strings.xml6
-rw-r--r--packages/SystemUI/res/values-is/strings.xml6
-rw-r--r--packages/SystemUI/res/values-it/strings.xml6
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml8
-rw-r--r--packages/SystemUI/res/values-km/strings.xml6
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml9
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml6
-rw-r--r--packages/SystemUI/res/values-my/strings.xml6
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-or/strings.xml9
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml6
-rw-r--r--packages/SystemUI/res/values-si/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw600dp/dimens.xml4
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml6
-rw-r--r--packages/SystemUI/res/values-te/strings.xml9
-rw-r--r--packages/SystemUI/res/values-television/colors.xml18
-rw-r--r--packages/SystemUI/res/values-television/dimens.xml41
-rw-r--r--packages/SystemUI/res/values-television/integers.xml2
-rw-r--r--packages/SystemUI/res/values-television/styles.xml30
-rw-r--r--packages/SystemUI/res/values-th/strings.xml6
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml6
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml6
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml6
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java51
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java390
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java279
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java145
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java197
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java46
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java7
-rw-r--r--packages/services/CameraExtensionsProxy/AndroidManifest.xml2
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java (renamed from packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java)2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java22
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java145
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java20
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java10
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java25
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java5
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java8
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java4
-rw-r--r--services/core/java/com/android/server/VpnManagerService.java9
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java10
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java7
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java63
-rw-r--r--services/core/java/com/android/server/app/GameManagerShellCommand.java72
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java21
-rw-r--r--services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java5
-rw-r--r--services/core/java/com/android/server/apphibernation/GlobalLevelState.java3
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java39
-rw-r--r--services/core/java/com/android/server/appop/DiscreteRegistry.java381
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java26
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java17
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java151
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java187
-rw-r--r--services/core/java/com/android/server/location/LocationShellCommand.java70
-rw-r--r--services/core/java/com/android/server/location/eventlog/LocationEventLog.java52
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java4
-rw-r--r--services/core/java/com/android/server/location/injector/Injector.java4
-rw-r--r--services/core/java/com/android/server/location/injector/SystemSettingsHelper.java2
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java91
-rw-r--r--services/core/java/com/android/server/location/settings/LocationSettings.java173
-rw-r--r--services/core/java/com/android/server/location/settings/LocationUserSettings.java98
-rw-r--r--services/core/java/com/android/server/location/settings/SettingsStore.java166
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java63
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java56
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java11
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java2
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java18
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java26
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java59
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java16
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java3
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java26
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java5
-rw-r--r--services/core/java/com/android/server/recoverysystem/RecoverySystemService.java4
-rw-r--r--services/core/java/com/android/server/vcn/Vcn.java4
-rw-r--r--services/core/java/com/android/server/vibrator/StepToRampAdapter.java76
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationSettings.java7
-rw-r--r--services/core/java/com/android/server/vibrator/VibrationThread.java14
-rw-r--r--services/core/java/com/android/server/vibrator/VibratorController.java38
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java34
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java165
-rw-r--r--services/core/java/com/android/server/wm/CompatModePackages.java112
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java19
-rw-r--r--services/core/java/com/android/server/wm/Task.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java5
-rw-r--r--services/core/jni/com_android_server_vibrator_VibratorController.cpp139
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd4
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt2
-rw-r--r--services/net/Android.bp1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java35
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java7
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java13
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java110
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java4
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java54
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java171
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java5
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java218
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java354
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java (renamed from services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java)47
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java167
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java28
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java58
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java69
-rw-r--r--services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java93
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java19
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java11
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java16
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskTests.java11
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java7
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java625
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java8
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java14
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java15
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl2
-rw-r--r--tests/Internal/src/android/app/WallpaperColorsTest.java23
-rw-r--r--tests/StagedInstallTest/Android.bp1
-rw-r--r--tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java20
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java22
-rw-r--r--tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java64
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTest.java21
585 files changed, 11385 insertions, 3101 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
index 4ef91b5e3bc1..b5e366255180 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSession.java
@@ -90,6 +90,7 @@ public final class AppSearchSession implements Closeable {
@NonNull Consumer<AppSearchResult<AppSearchSession>> callback) {
try {
mService.initialize(
+ mPackageName,
mUserHandle,
/*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
new IAppSearchResultCallback.Stub() {
@@ -136,8 +137,6 @@ public final class AppSearchSession implements Closeable {
* @param callback Callback to receive errors resulting from setting the schema. If the
* operation succeeds, the callback will be invoked with {@code null}.
*/
- // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
- // exposed.
public void setSchema(
@NonNull SetSchemaRequest request,
@NonNull Executor workExecutor,
@@ -152,7 +151,7 @@ public final class AppSearchSession implements Closeable {
for (AppSearchSchema schema : request.getSchemas()) {
schemaBundles.add(schema.getBundle());
}
- Map<String, List<Bundle>> schemasPackageAccessibleBundles =
+ Map<String, List<Bundle>> schemasVisibleToPackagesBundles =
new ArrayMap<>(request.getSchemasVisibleToPackagesInternal().size());
for (Map.Entry<String, Set<PackageIdentifier>> entry :
request.getSchemasVisibleToPackagesInternal().entrySet()) {
@@ -160,7 +159,7 @@ public final class AppSearchSession implements Closeable {
for (PackageIdentifier packageIdentifier : entry.getValue()) {
packageIdentifierBundles.add(packageIdentifier.getBundle());
}
- schemasPackageAccessibleBundles.put(entry.getKey(), packageIdentifierBundles);
+ schemasVisibleToPackagesBundles.put(entry.getKey(), packageIdentifierBundles);
}
// No need to trigger migration if user never set migrator
@@ -168,14 +167,14 @@ public final class AppSearchSession implements Closeable {
setSchemaNoMigrations(
request,
schemaBundles,
- schemasPackageAccessibleBundles,
+ schemasVisibleToPackagesBundles,
callbackExecutor,
callback);
} else {
setSchemaWithMigrations(
request,
schemaBundles,
- schemasPackageAccessibleBundles,
+ schemasVisibleToPackagesBundles,
workExecutor,
callbackExecutor,
callback);
@@ -687,7 +686,9 @@ public final class AppSearchSession implements Closeable {
if (mIsMutated && !mIsClosed) {
try {
mService.persistToDisk(
- mUserHandle, /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+ mPackageName,
+ mUserHandle,
+ /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the AppSearchSession", e);
@@ -704,7 +705,7 @@ public final class AppSearchSession implements Closeable {
private void setSchemaNoMigrations(
@NonNull SetSchemaRequest request,
@NonNull List<Bundle> schemaBundles,
- @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
+ @NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles,
@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
try {
@@ -713,7 +714,7 @@ public final class AppSearchSession implements Closeable {
mDatabaseName,
schemaBundles,
new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
- schemasPackageAccessibleBundles,
+ schemasVisibleToPackagesBundles,
request.isForceOverride(),
request.getVersion(),
mUserHandle,
@@ -761,7 +762,7 @@ public final class AppSearchSession implements Closeable {
private void setSchemaWithMigrations(
@NonNull SetSchemaRequest request,
@NonNull List<Bundle> schemaBundles,
- @NonNull Map<String, List<Bundle>> schemasPackageAccessibleBundles,
+ @NonNull Map<String, List<Bundle>> schemasVisibleToPackagesBundles,
@NonNull Executor workExecutor,
@NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull Consumer<AppSearchResult<SetSchemaResponse>> callback) {
@@ -787,7 +788,7 @@ public final class AppSearchSession implements Closeable {
// No need to trigger migration if no migrator is active.
if (activeMigrators.isEmpty()) {
- setSchemaNoMigrations(request, schemaBundles, schemasPackageAccessibleBundles,
+ setSchemaNoMigrations(request, schemaBundles, schemasVisibleToPackagesBundles,
callbackExecutor, callback);
return;
}
@@ -801,7 +802,7 @@ public final class AppSearchSession implements Closeable {
mDatabaseName,
schemaBundles,
new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
- schemasPackageAccessibleBundles,
+ schemasVisibleToPackagesBundles,
/*forceOverride=*/ false,
request.getVersion(),
mUserHandle,
@@ -853,7 +854,7 @@ public final class AppSearchSession implements Closeable {
mDatabaseName,
schemaBundles,
new ArrayList<>(request.getSchemasNotDisplayedBySystem()),
- schemasPackageAccessibleBundles,
+ schemasVisibleToPackagesBundles,
/*forceOverride=*/ true,
request.getVersion(),
mUserHandle,
diff --git a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
index 247eb08d698a..130e442c0000 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/GlobalSearchSession.java
@@ -73,6 +73,7 @@ public class GlobalSearchSession implements Closeable {
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
try {
mService.initialize(
+ mPackageName,
mUserHandle,
/*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime(),
new IAppSearchResultCallback.Stub() {
@@ -187,7 +188,9 @@ public class GlobalSearchSession implements Closeable {
if (mIsMutated && !mIsClosed) {
try {
mService.persistToDisk(
- mUserHandle, /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
+ mPackageName,
+ mUserHandle,
+ /*binderCallStartTimeMillis=*/ SystemClock.elapsedRealtime());
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the GlobalSearchSession", e);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
index eb5d22eaaea0..6dfa01f6e680 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResults.java
@@ -124,7 +124,8 @@ public class SearchResults implements Closeable {
wrapCallback(executor, callback));
}
} else {
- mService.getNextPage(mNextPageToken, mUserHandle, wrapCallback(executor, callback));
+ mService.getNextPage(mPackageName, mNextPageToken, mUserHandle,
+ wrapCallback(executor, callback));
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -135,7 +136,7 @@ public class SearchResults implements Closeable {
public void close() {
if (!mIsClosed) {
try {
- mService.invalidateNextPageToken(mNextPageToken, mUserHandle);
+ mService.invalidateNextPageToken(mPackageName, mNextPageToken, mUserHandle);
mIsClosed = true;
} catch (RemoteException e) {
Log.e(TAG, "Unable to close the SearchResults", e);
diff --git a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
index 0b26e146a7a4..a2f545f791fd 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
@@ -32,7 +32,7 @@ interface IAppSearchManager {
* @param schemaBundles List of {@link AppSearchSchema} bundles.
* @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform
* surfaces.
- * @param schemasPackageAccessibleBundles Schema types that are visible to the specified
+ * @param schemasVisibleToPackagesBundles Schema types that are visible to the specified
* packages. The value List contains PackageIdentifier Bundles.
* @param forceOverride Whether to apply the new schema even if it is incompatible. All
* incompatible documents will be deleted.
@@ -48,7 +48,7 @@ interface IAppSearchManager {
in String databaseName,
in List<Bundle> schemaBundles,
in List<String> schemasNotDisplayedBySystem,
- in Map<String, List<Bundle>> schemasPackageAccessibleBundles,
+ in Map<String, List<Bundle>> schemasVisibleToPackagesBundles,
boolean forceOverride,
in int schemaVersion,
in UserHandle userHandle,
@@ -181,21 +181,30 @@ interface IAppSearchManager {
* Fetches the next page of results of a previously executed query. Results can be empty if
* next-page token is invalid or all pages have been returned.
*
+ * @param packageName The name of the package to persist to disk for.
* @param nextPageToken The token of pre-loaded results of previously executed query.
* @param userHandle Handle of the calling user
* @param callback {@link AppSearchResult}&lt;{@link Bundle}&gt; of performing this
* operation.
*/
- void getNextPage(in long nextPageToken, in UserHandle userHandle, in IAppSearchResultCallback callback);
+ void getNextPage(
+ in String packageName,
+ in long nextPageToken,
+ in UserHandle userHandle,
+ in IAppSearchResultCallback callback);
/**
* Invalidates the next-page token so that no more results of the related query can be returned.
*
+ * @param packageName The name of the package to persist to disk for.
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
* @param userHandle Handle of the calling user
*/
- void invalidateNextPageToken(in long nextPageToken, in UserHandle userHandle);
+ void invalidateNextPageToken(
+ in String packageName,
+ in long nextPageToken,
+ in UserHandle userHandle);
/**
* Searches a document based on a given specifications.
@@ -336,20 +345,26 @@ interface IAppSearchManager {
/**
* Persists all update/delete requests to the disk.
*
+ * @param packageName The name of the package to persist to disk for.
* @param userHandle Handle of the calling user
* @param binderCallStartTimeMillis start timestamp of binder call in Millis
*/
- void persistToDisk(in UserHandle userHandle, in long binderCallStartTimeMillis);
+ void persistToDisk(
+ in String packageName,
+ in UserHandle userHandle,
+ in long binderCallStartTimeMillis);
/**
* Creates and initializes AppSearchImpl for the calling app.
*
+ * @param packageName The name of the package to initialize for.
* @param userHandle Handle of the calling user
* @param binderCallStartTimeMillis start timestamp of binder call in Millis
* @param callback {@link IAppSearchResultCallback#onResult} will be called with an
* {@link AppSearchResult}&lt;{@link Void}&gt;.
*/
void initialize(
+ in String packageName,
in UserHandle userHandle,
in long binderCallStartTimeMillis,
in IAppSearchResultCallback callback);
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
index 272e12db0124..d493a1c28a3a 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
@@ -96,17 +96,6 @@ public final class AppSearchBatchResult<KeyType, ValueType> {
return Collections.unmodifiableMap(mAll);
}
- /**
- * Asserts that this {@link AppSearchBatchResult} has no failures.
- *
- * @hide
- */
- public void checkSuccess() {
- if (!isSuccess()) {
- throw new IllegalStateException("AppSearchBatchResult has failures: " + this);
- }
- }
-
@Override
@NonNull
public String toString() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
index c57cf2e68993..b1cb132ee088 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchResult.java
@@ -239,6 +239,8 @@ public final class AppSearchResult<ValueType> {
resultCode = AppSearchResult.RESULT_INVALID_ARGUMENT;
} else if (t instanceof IOException) {
resultCode = AppSearchResult.RESULT_IO_ERROR;
+ } else if (t instanceof SecurityException) {
+ resultCode = AppSearchResult.RESULT_SECURITY_ERROR;
} else {
resultCode = AppSearchResult.RESULT_UNKNOWN_ERROR;
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
index 237e6242b22a..0ee5e65ef775 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchSchema.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.appsearch.exceptions.IllegalSchemaException;
import android.app.appsearch.util.BundleUtil;
+import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.util.ArraySet;
@@ -30,6 +31,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -67,8 +69,45 @@ public final class AppSearchSchema {
}
@Override
+ @NonNull
public String toString() {
- return mBundle.toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendAppSearchSchemaString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debugging string for the {@link AppSearchSchema} instance to the given string
+ * builder.
+ *
+ * @param builder the builder to append to.
+ */
+ private void appendAppSearchSchemaString(@NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder.append("properties: [\n");
+
+ AppSearchSchema.PropertyConfig[] sortedProperties =
+ getProperties().toArray(new AppSearchSchema.PropertyConfig[0]);
+ Arrays.sort(sortedProperties, (o1, o2) -> o1.getName().compareTo(o2.getName()));
+
+ for (int i = 0; i < sortedProperties.length; i++) {
+ AppSearchSchema.PropertyConfig propertyConfig = sortedProperties[i];
+ builder.increaseIndentLevel();
+ propertyConfig.appendPropertyConfigString(builder);
+ if (i != sortedProperties.length - 1) {
+ builder.append(",\n");
+ }
+ builder.decreaseIndentLevel();
+ }
+
+ builder.append("\n");
+ builder.append("]\n");
+ builder.decreaseIndentLevel();
+ builder.append("}");
}
/** Returns the name of this schema type, e.g. Email. */
@@ -255,7 +294,68 @@ public final class AppSearchSchema {
@Override
@NonNull
public String toString() {
- return mBundle.toString();
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendPropertyConfigString(stringBuilder);
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Appends a debug string for the {@link AppSearchSchema.PropertyConfig} instance to the
+ * given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendPropertyConfigString(@NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(builder);
+
+ builder.append("{\n");
+ builder.increaseIndentLevel();
+ builder.append("name: \"").append(getName()).append("\",\n");
+
+ if (this instanceof AppSearchSchema.StringPropertyConfig) {
+ ((StringPropertyConfig) this).appendStringPropertyConfigFields(builder);
+ } else if (this instanceof AppSearchSchema.DocumentPropertyConfig) {
+ ((DocumentPropertyConfig) this).appendDocumentPropertyConfigFields(builder);
+ }
+
+ switch (getCardinality()) {
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED:
+ builder.append("cardinality: CARDINALITY_REPEATED,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL:
+ builder.append("cardinality: CARDINALITY_OPTIONAL,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED:
+ builder.append("cardinality: CARDINALITY_REQUIRED,\n");
+ break;
+ default:
+ builder.append("cardinality: CARDINALITY_UNKNOWN,\n");
+ }
+
+ switch (getDataType()) {
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_STRING:
+ builder.append("dataType: DATA_TYPE_STRING,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_LONG:
+ builder.append("dataType: DATA_TYPE_LONG,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE:
+ builder.append("dataType: DATA_TYPE_DOUBLE,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN:
+ builder.append("dataType: DATA_TYPE_BOOLEAN,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES:
+ builder.append("dataType: DATA_TYPE_BYTES,\n");
+ break;
+ case AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT:
+ builder.append("dataType: DATA_TYPE_DOCUMENT,\n");
+ break;
+ default:
+ builder.append("dataType: DATA_TYPE_UNKNOWN,\n");
+ }
+ builder.decreaseIndentLevel();
+ builder.append("}");
}
/** Returns the name of this property. */
@@ -506,6 +606,41 @@ public final class AppSearchSchema {
return new StringPropertyConfig(bundle);
}
}
+
+ /**
+ * Appends a debug string for the {@link StringPropertyConfig} instance to the given string
+ * builder.
+ *
+ * <p>This appends fields specific to a {@link StringPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendStringPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ switch (getIndexingType()) {
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE:
+ builder.append("indexingType: INDEXING_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ builder.append("indexingType: INDEXING_TYPE_EXACT_TERMS,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES:
+ builder.append("indexingType: INDEXING_TYPE_PREFIXES,\n");
+ break;
+ default:
+ builder.append("indexingType: INDEXING_TYPE_UNKNOWN,\n");
+ }
+
+ switch (getTokenizerType()) {
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE:
+ builder.append("tokenizerType: TOKENIZER_TYPE_NONE,\n");
+ break;
+ case AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN:
+ builder.append("tokenizerType: TOKENIZER_TYPE_PLAIN,\n");
+ break;
+ default:
+ builder.append("tokenizerType: TOKENIZER_TYPE_UNKNOWN,\n");
+ }
+ }
}
/**
@@ -858,5 +993,21 @@ public final class AppSearchSchema {
return new DocumentPropertyConfig(bundle);
}
}
+
+ /**
+ * Appends a debug string for the {@link DocumentPropertyConfig} instance to the given
+ * string builder.
+ *
+ * <p>This appends fields specific to a {@link DocumentPropertyConfig} instance.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendDocumentPropertyConfigFields(@NonNull IndentingStringBuilder builder) {
+ builder.append("shouldIndexNestedProperties: ")
+ .append(shouldIndexNestedProperties())
+ .append(",\n");
+
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ }
}
}
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
index bcd341ec18a8..c905f95fe4c4 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/GenericDocument.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.appsearch.util.BundleUtil;
+import android.app.appsearch.util.IndentingStringBuilder;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Bundle;
import android.os.Parcelable;
@@ -50,9 +51,6 @@ import java.util.Set;
public class GenericDocument {
private static final String TAG = "AppSearchGenericDocumen";
- /** The maximum number of elements in a repeatable field. */
- private static final int MAX_REPEATED_PROPERTY_LENGTH = 100;
-
/** The maximum {@link String#length} of a {@link String} field. */
private static final int MAX_STRING_LENGTH = 20_000;
@@ -861,6 +859,7 @@ public class GenericDocument {
*
* @hide
*/
+ // TODO(b/171882200): Expose this API in Android T
@NonNull
public GenericDocument.Builder<GenericDocument.Builder<?>> toBuilder() {
Bundle clonedBundle = BundleUtil.deepCopy(mBundle);
@@ -890,121 +889,101 @@ public class GenericDocument {
@Override
@NonNull
public String toString() {
- StringBuilder stringBuilder = new StringBuilder();
- appendGenericDocumentString(this, /*indentLevel=*/ 0, stringBuilder);
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ appendGenericDocumentString(stringBuilder);
return stringBuilder.toString();
}
- private static void appendGenericDocumentString(
- @NonNull GenericDocument document, int indentLevel, @NonNull StringBuilder builder) {
- Objects.requireNonNull(document);
+ /**
+ * Appends a debug string for the {@link GenericDocument} instance to the given string builder.
+ *
+ * @param builder the builder to append to.
+ */
+ void appendGenericDocumentString(@NonNull IndentingStringBuilder builder) {
Objects.requireNonNull(builder);
- builder.append(getIndent(indentLevel)).append("{\n");
-
- String indent1 = getIndent(indentLevel + 1);
-
- builder.append(indent1)
- .append("namespace: \"")
- .append(document.getNamespace())
- .append("\",\n");
-
- builder.append(indent1).append("id: \"").append(document.getId()).append("\",\n");
-
- builder.append(indent1).append("score: ").append(document.getScore()).append(",\n");
-
- builder.append(indent1)
- .append("schemaType: \"")
- .append(document.getSchemaType())
- .append("\",\n");
-
- builder.append(indent1)
- .append("creationTimestampMillis: ")
- .append(document.getCreationTimestampMillis())
- .append(",\n");
+ builder.append("{\n");
+ builder.increaseIndentLevel();
- builder.append(indent1)
- .append("timeToLiveMillis: ")
- .append(document.getTtlMillis())
+ builder.append("namespace: \"").append(getNamespace()).append("\",\n");
+ builder.append("id: \"").append(getId()).append("\",\n");
+ builder.append("score: ").append(getScore()).append(",\n");
+ builder.append("schemaType: \"").append(getSchemaType()).append("\",\n");
+ builder.append("creationTimestampMillis: ")
+ .append(getCreationTimestampMillis())
.append(",\n");
+ builder.append("timeToLiveMillis: ").append(getTtlMillis()).append(",\n");
- builder.append(indent1).append("properties: {\n");
+ builder.append("properties: {\n");
- String[] sortedProperties = document.getPropertyNames().toArray(new String[0]);
+ String[] sortedProperties = getPropertyNames().toArray(new String[0]);
Arrays.sort(sortedProperties);
for (int i = 0; i < sortedProperties.length; i++) {
- Object property = document.getProperty(sortedProperties[i]);
- builder.append(getIndent(indentLevel + 2))
- .append("\"")
- .append(sortedProperties[i])
- .append("\"")
- .append(": ");
- appendPropertyString(property, indentLevel + 2, builder);
+ Object property = getProperty(sortedProperties[i]);
+ builder.increaseIndentLevel();
+ appendPropertyString(sortedProperties[i], property, builder);
if (i != sortedProperties.length - 1) {
builder.append(",\n");
}
+ builder.decreaseIndentLevel();
}
builder.append("\n");
- builder.append(indent1).append("}");
+ builder.append("}");
+ builder.decreaseIndentLevel();
builder.append("\n");
- builder.append(getIndent(indentLevel)).append("}");
+ builder.append("}");
}
/**
- * Appends a string for the given property to the given builder.
+ * Appends a debug string for the given document property to the given string builder.
*
+ * @param propertyName name of property to create string for.
* @param property property object to create string for.
- * @param indentLevel base indent level for property.
* @param builder the builder to append to.
*/
- private static void appendPropertyString(
- @NonNull Object property, int indentLevel, @NonNull StringBuilder builder) {
+ private void appendPropertyString(
+ @NonNull String propertyName,
+ @NonNull Object property,
+ @NonNull IndentingStringBuilder builder) {
+ Objects.requireNonNull(propertyName);
Objects.requireNonNull(property);
Objects.requireNonNull(builder);
- builder.append("[");
+ builder.append("\"").append(propertyName).append("\": [");
if (property instanceof GenericDocument[]) {
GenericDocument[] documentValues = (GenericDocument[]) property;
for (int i = 0; i < documentValues.length; ++i) {
builder.append("\n");
- appendGenericDocumentString(documentValues[i], indentLevel + 1, builder);
+ builder.increaseIndentLevel();
+ documentValues[i].appendGenericDocumentString(builder);
if (i != documentValues.length - 1) {
- builder.append(", ");
+ builder.append(",");
}
builder.append("\n");
+ builder.decreaseIndentLevel();
}
- builder.append(getIndent(indentLevel));
+ builder.append("]");
} else {
int propertyArrLength = Array.getLength(property);
for (int i = 0; i < propertyArrLength; i++) {
Object propertyElement = Array.get(property, i);
if (propertyElement instanceof String) {
- builder.append("\"").append(propertyElement).append("\"");
+ builder.append("\"").append((String) propertyElement).append("\"");
} else if (propertyElement instanceof byte[]) {
builder.append(Arrays.toString((byte[]) propertyElement));
} else {
- builder.append(propertyElement);
+ builder.append(propertyElement.toString());
}
if (i != propertyArrLength - 1) {
builder.append(", ");
+ } else {
+ builder.append("]");
}
}
}
-
- builder.append("]");
- }
-
- /** Appends a string for given indent level to the given builder. */
- @NonNull
- private static String getIndent(int indentLevel) {
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < indentLevel; ++i) {
- builder.append(" ");
- }
- return builder.toString();
}
/**
@@ -1187,8 +1166,8 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code String} values of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed
- * maximum repeated property length, or if a passed in {@code String} is {@code null}.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@code
+ * String} is {@code null}.
*/
@NonNull
public BuilderType setPropertyString(@NonNull String name, @NonNull String... values) {
@@ -1206,7 +1185,6 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code boolean} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyBoolean(@NonNull String name, @NonNull boolean... values) {
@@ -1223,7 +1201,6 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code long} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyLong(@NonNull String name, @NonNull long... values) {
@@ -1240,7 +1217,6 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code double} values of the property.
- * @throws IllegalArgumentException if values exceed maximum repeated property length.
*/
@NonNull
public BuilderType setPropertyDouble(@NonNull String name, @NonNull double... values) {
@@ -1257,8 +1233,8 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@code byte[]} of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed
- * maximum repeated property length, or if a passed in {@code byte[]} is {@code null}.
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@code
+ * byte[]} is {@code null}.
*/
@NonNull
public BuilderType setPropertyBytes(@NonNull String name, @NonNull byte[]... values) {
@@ -1276,8 +1252,7 @@ public class GenericDocument {
* @param name the name associated with the {@code values}. Must match the name for this
* property as given in {@link AppSearchSchema.PropertyConfig#getName}.
* @param values the {@link GenericDocument} values of the property.
- * @throws IllegalArgumentException if no values are provided, if provided values exceed if
- * provided values exceed maximum repeated property length, or if a passed in {@link
+ * @throws IllegalArgumentException if no values are provided, or if a passed in {@link
* GenericDocument} is {@code null}.
*/
@NonNull
@@ -1308,7 +1283,6 @@ public class GenericDocument {
private void putInPropertyBundle(@NonNull String name, @NonNull String[] values)
throws IllegalArgumentException {
- validateRepeatedPropertyLength(name, values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("The String at " + i + " is null.");
@@ -1327,17 +1301,14 @@ public class GenericDocument {
}
private void putInPropertyBundle(@NonNull String name, @NonNull boolean[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putBooleanArray(name, values);
}
private void putInPropertyBundle(@NonNull String name, @NonNull double[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putDoubleArray(name, values);
}
private void putInPropertyBundle(@NonNull String name, @NonNull long[] values) {
- validateRepeatedPropertyLength(name, values.length);
mProperties.putLongArray(name, values);
}
@@ -1348,7 +1319,6 @@ public class GenericDocument {
* into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
*/
private void putInPropertyBundle(@NonNull String name, @NonNull byte[][] values) {
- validateRepeatedPropertyLength(name, values.length);
ArrayList<Bundle> bundles = new ArrayList<>(values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
@@ -1362,7 +1332,6 @@ public class GenericDocument {
}
private void putInPropertyBundle(@NonNull String name, @NonNull GenericDocument[] values) {
- validateRepeatedPropertyLength(name, values.length);
Parcelable[] documentBundles = new Parcelable[values.length];
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
@@ -1373,18 +1342,6 @@ public class GenericDocument {
mProperties.putParcelableArray(name, documentBundles);
}
- private static void validateRepeatedPropertyLength(@NonNull String name, int length) {
- if (length > MAX_REPEATED_PROPERTY_LENGTH) {
- throw new IllegalArgumentException(
- "Repeated property \""
- + name
- + "\" has length "
- + length
- + ", which exceeds the limit of "
- + MAX_REPEATED_PROPERTY_LENGTH);
- }
- }
-
/** Builds the {@link GenericDocument} object. */
@NonNull
public GenericDocument build() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
index 0af3e7a8987a..b72ca9af42cb 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/SetSchemaRequest.java
@@ -169,13 +169,14 @@ public final class SetSchemaRequest {
/** Builder for {@link SetSchemaRequest} objects. */
public static final class Builder {
+ private static final int DEFAULT_VERSION = 1;
private ArraySet<AppSearchSchema> mSchemas = new ArraySet<>();
private ArraySet<String> mSchemasNotDisplayedBySystem = new ArraySet<>();
private ArrayMap<String, Set<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>();
private ArrayMap<String, Migrator> mMigrators = new ArrayMap<>();
private boolean mForceOverride = false;
- private int mVersion = 1;
+ private int mVersion = DEFAULT_VERSION;
private boolean mBuilt = false;
/**
@@ -384,6 +385,9 @@ public final class SetSchemaRequest {
* <p>The version number can stay the same, increase, or decrease relative to the current
* version number that is already stored in the {@link AppSearchSession} database.
*
+ * <p>The version of an empty database will always be 0. You cannot set version to the
+ * {@link SetSchemaRequest}, if it doesn't contains any {@link AppSearchSchema}.
+ *
* @param version A positive integer representing the version of the entire set of schemas
* represents the version of the whole schema in the {@link AppSearchSession} database,
* default version is 1.
@@ -423,7 +427,10 @@ public final class SetSchemaRequest {
throw new IllegalArgumentException(
"Schema types " + referencedSchemas + " referenced, but were not added.");
}
-
+ if (mSchemas.isEmpty() && mVersion != DEFAULT_VERSION) {
+ throw new IllegalArgumentException(
+ "Cannot set version to the request if schema is empty.");
+ }
mBuilt = true;
return new SetSchemaRequest(
mSchemas,
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java
new file mode 100644
index 000000000000..b494c3ce9337
--- /dev/null
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/IndentingStringBuilder.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app.appsearch.util;
+
+import android.annotation.NonNull;
+
+/**
+ * Utility for building indented strings.
+ *
+ * <p>This is a wrapper for {@link StringBuilder} for appending strings with indentation. The
+ * indentation level can be increased by calling {@link #increaseIndentLevel()} and decreased by
+ * calling {@link #decreaseIndentLevel()}.
+ *
+ * <p>Indentation is applied after each newline character for the given indent level.
+ *
+ * @hide
+ */
+public class IndentingStringBuilder {
+ private final StringBuilder mStringBuilder = new StringBuilder();
+
+ // Indicates whether next non-newline character should have an indent applied before it.
+ private boolean mIndentNext = false;
+ private int mIndentLevel = 0;
+
+ /** Increases the indent level by one for appended strings. */
+ @NonNull
+ public IndentingStringBuilder increaseIndentLevel() {
+ mIndentLevel++;
+ return this;
+ }
+
+ /** Decreases the indent level by one for appended strings. */
+ @NonNull
+ public IndentingStringBuilder decreaseIndentLevel() throws IllegalStateException {
+ if (mIndentLevel == 0) {
+ throw new IllegalStateException("Cannot set indent level below 0.");
+ }
+ mIndentLevel--;
+ return this;
+ }
+
+ /**
+ * Appends provided {@code String} at the current indentation level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull String str) {
+ applyIndentToString(str);
+ return this;
+ }
+
+ /**
+ * Appends provided {@code Object}, represented as a {@code String}, at the current indentation
+ * level.
+ *
+ * <p>Indentation is applied after each newline character.
+ */
+ @NonNull
+ public IndentingStringBuilder append(@NonNull Object obj) {
+ applyIndentToString(obj.toString());
+ return this;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mStringBuilder.toString();
+ }
+
+ /** Adds indent string to the {@link StringBuilder} instance for current indent level. */
+ private void applyIndent() {
+ for (int i = 0; i < mIndentLevel; i++) {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ /**
+ * Applies indent, for current indent level, after each newline character.
+ *
+ * <p>Consecutive newline characters are not indented.
+ */
+ private void applyIndentToString(@NonNull String str) {
+ int index = str.indexOf("\n");
+ if (index == 0) {
+ // String begins with new line character: append newline and slide past newline.
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > 1) {
+ applyIndentToString(str.substring(index + 1));
+ }
+ } else if (index >= 1) {
+ // String contains new line character: divide string between newline, append new line,
+ // and recurse on each string.
+ String beforeIndentString = str.substring(0, index);
+ applyIndentToString(beforeIndentString);
+ mStringBuilder.append("\n");
+ mIndentNext = true;
+ if (str.length() > index + 1) {
+ String afterIndentString = str.substring(index + 1);
+ applyIndentToString(afterIndentString);
+ }
+ } else {
+ // String does not contain newline character: append string.
+ if (mIndentNext) {
+ applyIndent();
+ mIndentNext = false;
+ }
+ mStringBuilder.append(str);
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 400c24138060..481d51eaf099 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -60,8 +60,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalManagerRegistry;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.util.PackageUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.android.server.usage.StorageStatsManagerLocal;
import com.android.server.usage.StorageStatsManagerLocal.StorageStatsAugmenter;
@@ -220,9 +220,10 @@ public class AppSearchManagerService extends SystemService {
}
// Only clear the package's data if AppSearch exists for this user.
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
//TODO(b/145759910) clear visibility setting for package.
instance.getAppSearchImpl().clearPackageData(packageName);
instance.getLogger().removeCachedUidForPackage(packageName);
@@ -243,11 +244,11 @@ public class AppSearchManagerService extends SystemService {
try {
// Only clear the package's data if AppSearch exists for this user.
if (AppSearchUserInstanceManager.getAppSearchDir(userHandle).exists()) {
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
- List<PackageInfo> installedPackageInfos = mContext
- .createContextAsUser(userHandle, /*flags=*/0)
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ List<PackageInfo> installedPackageInfos = userContext
.getPackageManager()
.getInstalledPackages(/*flags=*/0);
Set<String> packagesToKeep = new ArraySet<>(installedPackageInfos.size());
@@ -327,13 +328,15 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
List<AppSearchSchema> schemas = new ArrayList<>(schemaBundles.size());
for (int i = 0; i < schemaBundles.size(); i++) {
schemas.add(new AppSearchSchema(schemaBundles.get(i)));
}
- Map<String, List<PackageIdentifier>> schemasPackageAccessible =
+ Map<String, List<PackageIdentifier>> schemasVisibleToPackages =
new ArrayMap<>(schemasVisibleToPackagesBundles.size());
for (Map.Entry<String, List<Bundle>> entry :
schemasVisibleToPackagesBundles.entrySet()) {
@@ -343,7 +346,7 @@ public class AppSearchManagerService extends SystemService {
packageIdentifiers.add(
new PackageIdentifier(entry.getValue().get(i)));
}
- schemasPackageAccessible.put(entry.getKey(), packageIdentifiers);
+ schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers);
}
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
@@ -352,7 +355,7 @@ public class AppSearchManagerService extends SystemService {
schemas,
instance.getVisibilityStore(),
schemasNotDisplayedBySystem,
- schemasPackageAccessible,
+ schemasVisibleToPackages,
forceOverride,
schemaVersion);
++operationSuccessCount;
@@ -401,8 +404,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
GetSchemaResponse response =
@@ -431,8 +436,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
List<String> namespaces =
@@ -468,8 +475,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -548,8 +557,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Bundle> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -627,8 +638,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage = instance.getAppSearchImpl().query(
packageName,
@@ -691,8 +704,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
boolean callerHasSystemAccess =
@@ -738,9 +753,11 @@ public class AppSearchManagerService extends SystemService {
@Override
public void getNextPage(
+ @NonNull String packageName,
long nextPageToken,
@NonNull UserHandle userHandle,
@NonNull IAppSearchResultCallback callback) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(callback);
@@ -750,7 +767,10 @@ public class AppSearchManagerService extends SystemService {
// opened it
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
SearchResultPage searchResultPage =
@@ -765,14 +785,19 @@ public class AppSearchManagerService extends SystemService {
}
@Override
- public void invalidateNextPageToken(long nextPageToken, @NonNull UserHandle userHandle) {
+ public void invalidateNextPageToken(@NonNull String packageName, long nextPageToken,
+ @NonNull UserHandle userHandle) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
int callingUid = Binder.getCallingUid();
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().invalidateNextPageToken(nextPageToken);
@@ -803,7 +828,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
- verifyCallingPackage(callingUser, callingUid, packageName);
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
+ verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
// we don't need to append the file. The file is always brand new.
@@ -849,7 +877,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
- verifyCallingPackage(callingUser, callingUid, packageName);
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
+ verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -908,8 +939,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -957,8 +990,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchBatchResult.Builder<String, Void> resultBuilder =
new AppSearchBatchResult.Builder<>();
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
@@ -1039,8 +1074,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().removeByQuery(
packageName,
@@ -1095,8 +1132,10 @@ public class AppSearchManagerService extends SystemService {
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
EXECUTOR.execute(() -> {
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
- verifyCallingPackage(callingUser, callingUid, packageName);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(callingUser);
StorageInfo storageInfo = instance.getAppSearchImpl()
@@ -1112,8 +1151,10 @@ public class AppSearchManagerService extends SystemService {
@Override
public void persistToDisk(
+ @NonNull String packageName,
@NonNull UserHandle userHandle,
@ElapsedRealtimeLong long binderCallStartTimeMillis) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
@@ -1125,7 +1166,10 @@ public class AppSearchManagerService extends SystemService {
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getUserInstance(callingUser);
instance.getAppSearchImpl().persistToDisk(PersistType.Code.FULL);
++operationSuccessCount;
@@ -1157,24 +1201,30 @@ public class AppSearchManagerService extends SystemService {
@Override
public void initialize(
+ @NonNull String packageName,
@NonNull UserHandle userHandle,
@ElapsedRealtimeLong long binderCallStartTimeMillis,
@NonNull IAppSearchResultCallback callback) {
+ Objects.requireNonNull(packageName);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(callback);
long totalLatencyStartTimeMillis = SystemClock.elapsedRealtime();
int callingUid = Binder.getCallingUid();
UserHandle callingUser = handleIncomingUser(userHandle, callingUid);
+
EXECUTOR.execute(() -> {
@AppSearchResult.ResultCode int statusCode = AppSearchResult.RESULT_OK;
AppSearchUserInstance instance = null;
int operationSuccessCount = 0;
int operationFailureCount = 0;
try {
+ Context userContext = mContext.createContextAsUser(callingUser, /*flags=*/ 0);
verifyUserUnlocked(callingUser);
+ verifyCallingPackage(userContext, callingUser, callingUid, packageName);
+ verifyNotInstantApp(userContext, packageName);
instance = mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, callingUser, AppSearchConfig.getInstance(EXECUTOR));
++operationSuccessCount;
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
} catch (Throwable t) {
@@ -1204,14 +1254,15 @@ public class AppSearchManagerService extends SystemService {
}
private void verifyCallingPackage(
+ @NonNull Context userContext,
@NonNull UserHandle actualCallingUser,
int actualCallingUid,
@NonNull String claimedCallingPackage) {
Objects.requireNonNull(actualCallingUser);
Objects.requireNonNull(claimedCallingPackage);
- int claimedCallingUid = PackageUtil.getPackageUidAsUser(
- mContext, claimedCallingPackage, actualCallingUser);
+ int claimedCallingUid = PackageUtil.getPackageUid(
+ userContext, claimedCallingPackage);
if (claimedCallingUid == INVALID_UID) {
throw new SecurityException(
"Specified calling package [" + claimedCallingPackage + "] not found");
@@ -1317,6 +1368,21 @@ public class AppSearchManagerService extends SystemService {
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL);
}
+ /**
+ * Helper for ensuring instant apps can't make calls to AppSearch.
+ *
+ * @param userContext Context of the user making the call.
+ * @param packageName Package name of the caller.
+ * @throws SecurityException if the caller is an instant app.
+ */
+ private void verifyNotInstantApp(@NonNull Context userContext, @NonNull String packageName) {
+ PackageManager callingPackageManager = userContext.getPackageManager();
+ if (callingPackageManager.isInstantApp(packageName)) {
+ throw new SecurityException("Caller not allowed to create AppSearch session"
+ + "; userHandle=" + userContext.getUser() + ", callingPackage=" + packageName);
+ }
+ }
+
// TODO(b/179160886): Cache the previous storage stats.
private class AppSearchStorageStatsAugmenter implements StorageStatsAugmenter {
@Override
@@ -1331,9 +1397,10 @@ public class AppSearchManagerService extends SystemService {
try {
verifyUserUnlocked(userHandle);
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packageName).getSizeBytes();
} catch (Throwable t) {
@@ -1359,9 +1426,10 @@ public class AppSearchManagerService extends SystemService {
if (packagesForUid == null) {
return;
}
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUid.length; i++) {
stats.dataSize += instance.getAppSearchImpl()
.getStorageInfoForPackage(packagesForUid[i]).getSizeBytes();
@@ -1387,9 +1455,10 @@ public class AppSearchManagerService extends SystemService {
if (packagesForUser == null) {
return;
}
+ Context userContext = mContext.createContextAsUser(userHandle, /*flags=*/ 0);
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getOrCreateUserInstance(
- mContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
+ userContext, userHandle, AppSearchConfig.getInstance(EXECUTOR));
for (int i = 0; i < packagesForUser.size(); i++) {
String packageName = packagesForUser.get(i).packageName;
stats.dataSize += instance.getAppSearchImpl()
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
index 7e743edaf3ee..56e2af5fa2e3 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstance.java
@@ -19,7 +19,7 @@ import android.annotation.NonNull;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.stats.PlatformLogger;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import java.util.Objects;
@@ -30,12 +30,12 @@ import java.util.Objects;
public final class AppSearchUserInstance {
private final PlatformLogger mLogger;
private final AppSearchImpl mAppSearchImpl;
- private final VisibilityStore mVisibilityStore;
+ private final VisibilityStoreImpl mVisibilityStore;
AppSearchUserInstance(
@NonNull PlatformLogger logger,
@NonNull AppSearchImpl appSearchImpl,
- @NonNull VisibilityStore visibilityStore) {
+ @NonNull VisibilityStoreImpl visibilityStore) {
mLogger = Objects.requireNonNull(logger);
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mVisibilityStore = Objects.requireNonNull(visibilityStore);
@@ -52,7 +52,7 @@ public final class AppSearchUserInstance {
}
@NonNull
- public VisibilityStore getVisibilityStore() {
+ public VisibilityStoreImpl getVisibilityStore() {
return mVisibilityStore;
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
index cedc364f6072..e067d4bcdf72 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchUserInstanceManager.java
@@ -30,7 +30,7 @@ import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.FrameworkOptimizeStrategy;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
import com.android.server.appsearch.stats.PlatformLogger;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import java.io.File;
import java.util.Map;
@@ -89,25 +89,24 @@ public final class AppSearchUserInstanceManager {
* <p>If no AppSearchUserInstance exists for the unlocked user, Icing will be initialized and
* one will be created.
*
- * @param context The context
+ * @param userContext Context of the user calling AppSearch
* @param userHandle The multi-user handle of the device user calling AppSearch
* @param config Flag manager for AppSearch
* @return An initialized {@link AppSearchUserInstance} for this user
*/
@NonNull
public AppSearchUserInstance getOrCreateUserInstance(
- @NonNull Context context,
+ @NonNull Context userContext,
@NonNull UserHandle userHandle,
@NonNull AppSearchConfig config)
throws AppSearchException {
- Objects.requireNonNull(context);
+ Objects.requireNonNull(userContext);
Objects.requireNonNull(userHandle);
Objects.requireNonNull(config);
synchronized (mInstancesLocked) {
AppSearchUserInstance instance = mInstancesLocked.get(userHandle);
if (instance == null) {
- Context userContext = context.createContextAsUser(userHandle, /*flags=*/ 0);
instance = createUserInstance(userContext, userHandle, config);
mInstancesLocked.put(userHandle, instance);
}
@@ -169,7 +168,7 @@ public final class AppSearchUserInstanceManager {
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
// Initialize the classes that make up AppSearchUserInstance
- PlatformLogger logger = new PlatformLogger(userContext, userHandle, config);
+ PlatformLogger logger = new PlatformLogger(userContext, config);
File appSearchDir = getAppSearchDir(userHandle);
File icingDir = new File(appSearchDir, "icing");
@@ -178,7 +177,8 @@ public final class AppSearchUserInstanceManager {
AppSearchImpl.create(icingDir, initStatsBuilder, new FrameworkOptimizeStrategy());
long prepareVisibilityStoreLatencyStartMillis = SystemClock.elapsedRealtime();
- VisibilityStore visibilityStore = VisibilityStore.create(appSearchImpl, userContext);
+ VisibilityStoreImpl visibilityStore =
+ VisibilityStoreImpl.create(appSearchImpl, userContext);
long prepareVisibilityStoreLatencyEndMillis = SystemClock.elapsedRealtime();
initStatsBuilder
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 77a1bb402bd3..9dee179bd6f2 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -58,7 +58,7 @@ import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.google.android.icing.IcingSearchEngine;
import com.google.android.icing.proto.DeleteByQueryResultProto;
@@ -346,11 +346,11 @@ public final class AppSearchImpl implements Closeable {
* @param packageName The package name that owns the schemas.
* @param databaseName The name of the database where this schema lives.
* @param schemas Schemas to set for this app.
- * @param visibilityStore If set, {@code schemasNotPlatformSurfaceable} and {@code
- * schemasPackageAccessible} will be saved here if the schema is successfully applied.
- * @param schemasNotPlatformSurfaceable Schema types that should not be surfaced on platform
+ * @param visibilityStore If set, {@code schemasNotDisplayedBySystem} and {@code
+ * schemasVisibleToPackages} will be saved here if the schema is successfully applied.
+ * @param schemasNotDisplayedBySystem Schema types that should not be surfaced on platform
* surfaces.
- * @param schemasPackageAccessible Schema types that are visible to the specified packages.
+ * @param schemasVisibleToPackages Schema types that are visible to the specified packages.
* @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
* which do not comply with the new schema will be deleted.
* @param version The overall version number of the request.
@@ -366,8 +366,8 @@ public final class AppSearchImpl implements Closeable {
@NonNull String databaseName,
@NonNull List<AppSearchSchema> schemas,
@Nullable VisibilityStore visibilityStore,
- @NonNull List<String> schemasNotPlatformSurfaceable,
- @NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible,
+ @NonNull List<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages,
boolean forceOverride,
int version)
throws AppSearchException {
@@ -430,25 +430,25 @@ public final class AppSearchImpl implements Closeable {
}
if (visibilityStore != null) {
- Set<String> prefixedSchemasNotPlatformSurfaceable =
- new ArraySet<>(schemasNotPlatformSurfaceable.size());
- for (int i = 0; i < schemasNotPlatformSurfaceable.size(); i++) {
- prefixedSchemasNotPlatformSurfaceable.add(
- prefix + schemasNotPlatformSurfaceable.get(i));
+ Set<String> prefixedSchemasNotDisplayedBySystem =
+ new ArraySet<>(schemasNotDisplayedBySystem.size());
+ for (int i = 0; i < schemasNotDisplayedBySystem.size(); i++) {
+ prefixedSchemasNotDisplayedBySystem.add(
+ prefix + schemasNotDisplayedBySystem.get(i));
}
- Map<String, List<PackageIdentifier>> prefixedSchemasPackageAccessible =
- new ArrayMap<>(schemasPackageAccessible.size());
+ Map<String, List<PackageIdentifier>> prefixedSchemasVisibleToPackages =
+ new ArrayMap<>(schemasVisibleToPackages.size());
for (Map.Entry<String, List<PackageIdentifier>> entry :
- schemasPackageAccessible.entrySet()) {
- prefixedSchemasPackageAccessible.put(prefix + entry.getKey(), entry.getValue());
+ schemasVisibleToPackages.entrySet()) {
+ prefixedSchemasVisibleToPackages.put(prefix + entry.getKey(), entry.getValue());
}
visibilityStore.setVisibility(
packageName,
databaseName,
- prefixedSchemasNotPlatformSurfaceable,
- prefixedSchemasPackageAccessible);
+ prefixedSchemasNotDisplayedBySystem,
+ prefixedSchemasVisibleToPackages);
}
return SetSchemaResponseToProtoConverter.toSetSchemaResponse(
@@ -737,6 +737,9 @@ public final class AppSearchImpl implements Closeable {
if (!filterPackageNames.isEmpty() && !filterPackageNames.contains(packageName)) {
// Client wanted to query over some packages that weren't its own. This isn't
// allowed through local query so we can return early with no results.
+ if (logger != null) {
+ sStatsBuilder.setStatusCode(AppSearchResult.RESULT_SECURITY_ERROR);
+ }
return new SearchResultPage(Bundle.EMPTY);
}
@@ -768,7 +771,7 @@ public final class AppSearchImpl implements Closeable {
* @param queryExpression Query String to search.
* @param searchSpec Spec for setting filters, raw query etc.
* @param callerPackageName Package name of the caller, should belong to the {@code
- * userContext}.
+ * callerUserHandle}.
* @param visibilityStore Optional visibility store to obtain system and package visibility
* settings from
* @param callerUid UID of the client making the globalQuery call.
@@ -1465,7 +1468,6 @@ public final class AppSearchImpl implements Closeable {
mOptimizeIntervalCountLocked = 0;
mSchemaMapLocked.clear();
mNamespaceMapLocked.clear();
-
if (initStatsBuilder != null) {
initStatsBuilder
.setHasReset(true)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java
new file mode 100644
index 000000000000..6e1e2d5f774b
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SchemaMigrationStats.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.appsearch.external.localstorage.stats;
+
+import android.annotation.NonNull;
+import android.app.appsearch.SetSchemaRequest;
+
+import java.util.Objects;
+
+/**
+ * Class holds detailed stats for Schema migration.
+ *
+ * @hide
+ */
+// TODO(b/173532925): Hides getter and setter functions for accessing {@code
+// mFirstSetSchemaLatencyMillis} and {@code mSecondSetSchemaLatencyMillis} field.
+
+public final class SchemaMigrationStats {
+ /** GetSchema latency in milliseconds. */
+ private final int mGetSchemaLatencyMillis;
+
+ /**
+ * Latency of querying all documents that need to be migrated to new version and transforming
+ * documents to new version in milliseconds.
+ */
+ private final int mQueryAndTransformLatencyMillis;
+
+ private final int mFirstSetSchemaLatencyMillis;
+
+ private final int mSecondSetSchemaLatencyMillis;
+
+ /** Latency of putting migrated document to Icing lib in milliseconds. */
+ private final int mSaveDocumentLatencyMillis;
+
+ private final int mMigratedDocumentCount;
+
+ private final int mSavedDocumentCount;
+
+ SchemaMigrationStats(@NonNull Builder builder) {
+ Objects.requireNonNull(builder);
+ mGetSchemaLatencyMillis = builder.mGetSchemaLatencyMillis;
+ mQueryAndTransformLatencyMillis = builder.mQueryAndTransformLatencyMillis;
+ mFirstSetSchemaLatencyMillis = builder.mFirstSetSchemaLatencyMillis;
+ mSecondSetSchemaLatencyMillis = builder.mSecondSetSchemaLatencyMillis;
+ mSaveDocumentLatencyMillis = builder.mSaveDocumentLatencyMillis;
+ mMigratedDocumentCount = builder.mMigratedDocumentCount;
+ mSavedDocumentCount = builder.mSavedDocumentCount;
+ }
+
+ /** Returns GetSchema latency in milliseconds. */
+ public int getGetSchemaLatencyMillis() {
+ return mGetSchemaLatencyMillis;
+ }
+
+ /**
+ * Returns latency of querying all documents that need to be migrated to new version and
+ * transforming documents to new version in milliseconds.
+ */
+ public int getQueryAndTransformLatencyMillis() {
+ return mQueryAndTransformLatencyMillis;
+ }
+
+ /**
+ * Returns latency of first SetSchema action in milliseconds.
+ *
+ * <p>If all schema fields are backward compatible, the schema will be successful set to Icing.
+ * Otherwise, we will retrieve incompatible types here.
+ *
+ * <p>Please see {@link SetSchemaRequest} for what is "incompatible".
+ */
+ public int getFirstSetSchemaLatencyMillis() {
+ return mFirstSetSchemaLatencyMillis;
+ }
+
+ /**
+ * Returns latency of second SetSchema action in milliseconds.
+ *
+ * <p>If all schema fields are backward compatible, the schema will be successful set to Icing
+ * in the first setSchema action and this value will be 0. Otherwise, schema types will be set
+ * to Icing by this action.
+ */
+ public int getSecondSetSchemaLatencyMillis() {
+ return mSecondSetSchemaLatencyMillis;
+ }
+
+ /** Returns latency of putting migrated document to Icing lib in milliseconds. */
+ public int getSaveDocumentLatencyMillis() {
+ return mSaveDocumentLatencyMillis;
+ }
+
+ /** Returns number of migrated documents. */
+ public int getMigratedDocumentCount() {
+ return mMigratedDocumentCount;
+ }
+
+ /** Returns number of updated documents which are saved in Icing lib. */
+ public int getSavedDocumentCount() {
+ return mSavedDocumentCount;
+ }
+
+ /** Builder for {@link SchemaMigrationStats}. */
+ public static class Builder {
+ int mGetSchemaLatencyMillis;
+ int mQueryAndTransformLatencyMillis;
+ int mFirstSetSchemaLatencyMillis;
+ int mSecondSetSchemaLatencyMillis;
+ int mSaveDocumentLatencyMillis;
+ int mMigratedDocumentCount;
+ int mSavedDocumentCount;
+
+ /** Sets latency for the GetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setGetSchemaLatencyMillis(int getSchemaLatencyMillis) {
+ mGetSchemaLatencyMillis = getSchemaLatencyMillis;
+ return this;
+ }
+
+ /**
+ * Sets latency for querying all documents that need to be migrated to new version and
+ * transforming documents to new version in milliseconds.
+ */
+ @NonNull
+ public SchemaMigrationStats.Builder setQueryAndTransformLatencyMillis(
+ int queryAndTransformLatencyMillis) {
+ mQueryAndTransformLatencyMillis = queryAndTransformLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency of first SetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setFirstSetSchemaLatencyMillis(
+ int firstSetSchemaLatencyMillis) {
+ mFirstSetSchemaLatencyMillis = firstSetSchemaLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency of second SetSchema action in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSecondSetSchemaLatencyMillis(
+ int secondSetSchemaLatencyMillis) {
+ mSecondSetSchemaLatencyMillis = secondSetSchemaLatencyMillis;
+ return this;
+ }
+
+ /** Sets latency for putting migrated document to Icing lib in milliseconds. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSaveDocumentLatencyMillis(
+ int saveDocumentLatencyMillis) {
+ mSaveDocumentLatencyMillis = saveDocumentLatencyMillis;
+ return this;
+ }
+
+ /** Sets number of migrated documents. */
+ @NonNull
+ public SchemaMigrationStats.Builder setMigratedDocumentCount(int migratedDocumentCount) {
+ mMigratedDocumentCount = migratedDocumentCount;
+ return this;
+ }
+
+ /** Sets number of updated documents which are saved in Icing lib. */
+ @NonNull
+ public SchemaMigrationStats.Builder setSavedDocumentCount(int savedDocumentCount) {
+ mSavedDocumentCount = savedDocumentCount;
+ return this;
+ }
+
+ /**
+ * Builds a new {@link SchemaMigrationStats} from the {@link SchemaMigrationStats.Builder}.
+ */
+ @NonNull
+ public SchemaMigrationStats build() {
+ return new SchemaMigrationStats(/* builder= */ this);
+ }
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
index 56a546a2e8e1..9d789a894855 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
@@ -17,6 +17,7 @@
package com.android.server.appsearch.external.localstorage.stats;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.appsearch.AppSearchResult;
import java.util.Objects;
@@ -38,6 +39,12 @@ public final class SetSchemaStats {
*/
@AppSearchResult.ResultCode private final int mStatusCode;
+ /**
+ * Stores stats of SchemaMigration in SetSchema process. Is {@code null} if no schema migration
+ * is needed.
+ */
+ @Nullable private final SchemaMigrationStats mSchemaMigrationStats;
+
private final int mTotalLatencyMillis;
/** Overall time used for the native function call. */
@@ -63,6 +70,7 @@ public final class SetSchemaStats {
mPackageName = builder.mPackageName;
mDatabase = builder.mDatabase;
mStatusCode = builder.mStatusCode;
+ mSchemaMigrationStats = builder.mSchemaMigrationStats;
mTotalLatencyMillis = builder.mTotalLatencyMillis;
mNativeLatencyMillis = builder.mNativeLatencyMillis;
mNewTypeCount = builder.mNewTypeCount;
@@ -90,6 +98,15 @@ public final class SetSchemaStats {
return mStatusCode;
}
+ /**
+ * Returns the status of schema migration, if migration is executed during the SetSchema
+ * process. Otherwise, returns {@code null}.
+ */
+ @Nullable
+ public SchemaMigrationStats getSchemaMigrationStats() {
+ return mSchemaMigrationStats;
+ }
+
/** Returns the total latency of the SetSchema action. */
public int getTotalLatencyMillis() {
return mTotalLatencyMillis;
@@ -140,6 +157,7 @@ public final class SetSchemaStats {
@NonNull final String mPackageName;
@NonNull final String mDatabase;
@AppSearchResult.ResultCode int mStatusCode;
+ @Nullable SchemaMigrationStats mSchemaMigrationStats;
int mTotalLatencyMillis;
int mNativeLatencyMillis;
int mNewTypeCount;
@@ -161,7 +179,14 @@ public final class SetSchemaStats {
return this;
}
- /** Sets total latency for the SetSchema action. */
+ /** Sets the status of schema migration. */
+ @NonNull
+ public Builder setSchemaMigrationStats(@NonNull SchemaMigrationStats schemaMigrationStats) {
+ mSchemaMigrationStats = Objects.requireNonNull(schemaMigrationStats);
+ return this;
+ }
+
+ /** Sets total latency for the SetSchema action in milliseconds. */
@NonNull
public Builder setTotalLatencyMillis(int totalLatencyMillis) {
mTotalLatencyMillis = totalLatencyMillis;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java
new file mode 100644
index 000000000000..fb89250cb096
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/visibilitystore/VisibilityStore.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.appsearch.external.localstorage.visibilitystore;
+
+import android.annotation.NonNull;
+import android.app.appsearch.PackageIdentifier;
+import android.app.appsearch.exceptions.AppSearchException;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An interface for classes that store and validate document visibility data.
+ *
+ * @hide
+ */
+public interface VisibilityStore {
+ /**
+ * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
+ * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
+ */
+ String PACKAGE_NAME = "VS#Pkg";
+
+ @VisibleForTesting String DATABASE_NAME = "VS#Db";
+
+ /**
+ * Sets visibility settings for the given database. Any previous visibility settings will be
+ * overwritten.
+ *
+ * @param packageName Package of app that owns the schemas.
+ * @param databaseName Database that owns the schemas.
+ * @param schemasNotDisplayedBySystem Set of prefixed schemas that should be hidden from
+ * platform surfaces.
+ * @param schemasVisibleToPackages Map of prefixed schemas to a list of package identifiers that
+ * have access to the schema.
+ * @throws AppSearchException on AppSearchImpl error.
+ */
+ void setVisibility(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull Set<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages)
+ throws AppSearchException;
+
+ /**
+ * Checks whether the given package has access to system-surfaceable schemas.
+ *
+ * @param callerUid UID of the app that wants to see the data.
+ */
+ boolean isSchemaSearchableByCaller(
+ @NonNull String packageName,
+ @NonNull String databaseName,
+ @NonNull String prefixedSchema,
+ int callerUid,
+ boolean callerHasSystemAccess);
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index 31fead5e6314..322bd119b604 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -22,7 +22,6 @@ import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Process;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
@@ -55,11 +54,8 @@ import java.util.Random;
public final class PlatformLogger implements AppSearchLogger {
private static final String TAG = "AppSearchPlatformLogger";
- // Context of the system service.
- private final Context mContext;
-
- // User we're logging for.
- private final UserHandle mUserHandle;
+ // Context of the user we're logging for.
+ private final Context mUserContext;
// Manager holding the configuration flags
private final AppSearchConfig mConfig;
@@ -120,10 +116,9 @@ public final class PlatformLogger implements AppSearchLogger {
* Westworld constructor
*/
public PlatformLogger(
- @NonNull Context context, @NonNull UserHandle userHandle,
+ @NonNull Context userContext,
@NonNull AppSearchConfig config) {
- mContext = Objects.requireNonNull(context);
- mUserHandle = Objects.requireNonNull(userHandle);
+ mUserContext = Objects.requireNonNull(userContext);
mConfig = Objects.requireNonNull(config);
}
@@ -451,7 +446,7 @@ public final class PlatformLogger implements AppSearchLogger {
private int getPackageUidAsUserLocked(@NonNull String packageName) {
Integer packageUid = mPackageUidCacheLocked.get(packageName);
if (packageUid == null) {
- packageUid = PackageUtil.getPackageUidAsUser(mContext, packageName, mUserHandle);
+ packageUid = PackageUtil.getPackageUid(mUserContext, packageName);
if (packageUid != Process.INVALID_UID) {
mPackageUidCacheLocked.put(packageName, packageUid);
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java b/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
index 53a1bedb780b..714ffb6c8b68 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/util/PackageUtil.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Process;
-import android.os.UserHandle;
/**
* Utilities for interacting with {@link android.content.pm.PackageManager},
@@ -32,16 +31,6 @@ public class PackageUtil {
private PackageUtil() {}
/**
- * Finds the UID of the {@code packageName}. Returns {@link Process#INVALID_UID} if unable to
- * find the UID.
- */
- public static int getPackageUidAsUser(
- @NonNull Context context, @NonNull String packageName, @NonNull UserHandle user) {
- Context userContext = context.createContextAsUser(user, /*flags=*/ 0);
- return getPackageUid(userContext, packageName);
- }
-
- /**
* Finds the UID of the {@code packageName} in the given {@code context}. Returns
* {@link Process#INVALID_UID} if unable to find the UID.
*/
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotDisplayedBySystemMap.java
index 9e36fd02569f..95905af76123 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotPlatformSurfaceableMap.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/NotDisplayedBySystemMap.java
@@ -27,7 +27,7 @@ import java.util.Set;
*
* This object is not thread safe.
*/
-class NotPlatformSurfaceableMap {
+class NotDisplayedBySystemMap {
/**
* Maps packages to databases to the set of prefixed schemas that are platform-hidden within
* that database.
@@ -39,7 +39,7 @@ class NotPlatformSurfaceableMap {
*
* <p>Any existing mappings for this prefix are overwritten.
*/
- public void setNotPlatformSurfaceable(
+ public void setNotDisplayedBySystem(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull Set<String> prefixedSchemas) {
@@ -55,7 +55,7 @@ class NotPlatformSurfaceableMap {
* Returns whether the given prefixed schema is platform surfaceable (has not opted out) in the
* given database.
*/
- public boolean isSchemaPlatformSurfaceable(
+ public boolean isSchemaDisplayedBySystem(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java
index 1771b1ddc6b6..b0108704be34 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityDocument.java
@@ -28,10 +28,10 @@ class VisibilityDocument extends GenericDocument {
/**
* Property that holds the list of platform-hidden schemas, as part of the visibility settings.
*/
- private static final String NOT_PLATFORM_SURFACEABLE_PROPERTY = "notPlatformSurfaceable";
+ private static final String NOT_DISPLAYED_BY_SYSTEM_PROPERTY = "notPlatformSurfaceable";
/** Property that holds nested documents of package accessible schemas. */
- private static final String PACKAGE_ACCESSIBLE_PROPERTY = "packageAccessible";
+ private static final String VISIBLE_TO_PACKAGES_PROPERTY = "packageAccessible";
/**
* Schema for the VisibilityStore's documents.
@@ -41,11 +41,11 @@ class VisibilityDocument extends GenericDocument {
*/
public static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
.addProperty(new AppSearchSchema.StringPropertyConfig.Builder(
- NOT_PLATFORM_SURFACEABLE_PROPERTY)
+ NOT_DISPLAYED_BY_SYSTEM_PROPERTY)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.addProperty(new AppSearchSchema.DocumentPropertyConfig.Builder(
- PACKAGE_ACCESSIBLE_PROPERTY, PackageAccessibleDocument.SCHEMA_TYPE)
+ VISIBLE_TO_PACKAGES_PROPERTY, VisibleToPackagesDocument.SCHEMA_TYPE)
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
.build())
.build();
@@ -55,13 +55,13 @@ class VisibilityDocument extends GenericDocument {
}
@Nullable
- public String[] getNotPlatformSurfaceableSchemas() {
- return getPropertyStringArray(NOT_PLATFORM_SURFACEABLE_PROPERTY);
+ public String[] getNotDisplayedBySystem() {
+ return getPropertyStringArray(NOT_DISPLAYED_BY_SYSTEM_PROPERTY);
}
@Nullable
- public GenericDocument[] getPackageAccessibleSchemas() {
- return getPropertyDocumentArray(PACKAGE_ACCESSIBLE_PROPERTY);
+ public GenericDocument[] getVisibleToPackages() {
+ return getPropertyDocumentArray(VISIBLE_TO_PACKAGES_PROPERTY);
}
/** Builder for {@link VisibilityDocument}. */
@@ -72,17 +72,15 @@ class VisibilityDocument extends GenericDocument {
/** Sets which prefixed schemas have opted out of platform surfacing. */
@NonNull
- public Builder setSchemasNotPlatformSurfaceable(
- @NonNull String[] notPlatformSurfaceableSchemas) {
- return setPropertyString(
- NOT_PLATFORM_SURFACEABLE_PROPERTY, notPlatformSurfaceableSchemas);
+ public Builder setNotDisplayedBySystem(@NonNull String[] notDisplayedBySystemSchemas) {
+ return setPropertyString(NOT_DISPLAYED_BY_SYSTEM_PROPERTY, notDisplayedBySystemSchemas);
}
/** Sets which prefixed schemas have configured package access. */
@NonNull
- public Builder setPackageAccessibleSchemas(
- @NonNull PackageAccessibleDocument[] packageAccessibleSchemas) {
- return setPropertyDocument(PACKAGE_ACCESSIBLE_PROPERTY, packageAccessibleSchemas);
+ public Builder setVisibleToPackages(
+ @NonNull VisibleToPackagesDocument[] visibleToPackagesDocuments) {
+ return setPropertyDocument(VISIBLE_TO_PACKAGES_PROPERTY, visibleToPackagesDocuments);
}
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
index ae1ec56b4ee6..ce142d646d1c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStore.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
@@ -30,9 +30,9 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.android.server.appsearch.util.PackageUtil;
import com.google.android.icing.proto.PersistType;
@@ -60,26 +60,12 @@ import java.util.Set;
* <p>This class doesn't handle any locking itself. Its callers should handle the locking at a
* higher level.
*
- * <p>NOTE: This class holds an instance of AppSearchImpl and AppSearchImpl holds an instance of
- * this class. Take care to not cause any circular dependencies.
- *
* @hide
*/
-public class VisibilityStore {
- /** No-op uid that won't have any visibility settings. */
- public static final int NO_OP_UID = -1;
-
+public class VisibilityStoreImpl implements VisibilityStore {
/** Version for the visibility schema */
private static final int SCHEMA_VERSION = 0;
- /**
- * These cannot have any of the special characters used by AppSearchImpl (e.g. {@code
- * AppSearchImpl#PACKAGE_DELIMITER} or {@code AppSearchImpl#DATABASE_DELIMITER}.
- */
- public static final String PACKAGE_NAME = "VS#Pkg";
-
- @VisibleForTesting public static final String DATABASE_NAME = "VS#Db";
-
/** Namespace of documents that contain visibility settings */
private static final String NAMESPACE = "";
@@ -92,11 +78,10 @@ public class VisibilityStore {
private final Context mUserContext;
/** Stores the schemas that are platform-hidden. All values are prefixed. */
- private final NotPlatformSurfaceableMap mNotPlatformSurfaceableMap =
- new NotPlatformSurfaceableMap();
+ private final NotDisplayedBySystemMap mNotDisplayedBySystemMap = new NotDisplayedBySystemMap();
- /** Stores the schemas that are package accessible. All values are prefixed. */
- private final PackageAccessibleMap mPackageAccessibleMap = new PackageAccessibleMap();
+ /** Stores the schemas that are visible to 3p packages. All values are prefixed. */
+ private final VisibleToPackagesMap mVisibleToPackagesMap = new VisibleToPackagesMap();
/**
* Creates and initializes VisibilityStore.
@@ -105,41 +90,41 @@ public class VisibilityStore {
* @param userContext Context of the user that the call is being made as
*/
@NonNull
- public static VisibilityStore create(
+ public static VisibilityStoreImpl create(
@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
- return new VisibilityStore(appSearchImpl, userContext);
+ return new VisibilityStoreImpl(appSearchImpl, userContext);
}
- private VisibilityStore(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
+ private VisibilityStoreImpl(@NonNull AppSearchImpl appSearchImpl, @NonNull Context userContext)
throws AppSearchException {
mAppSearchImpl = Objects.requireNonNull(appSearchImpl);
mUserContext = Objects.requireNonNull(userContext);
GetSchemaResponse getSchemaResponse = mAppSearchImpl.getSchema(PACKAGE_NAME, DATABASE_NAME);
boolean hasVisibilityType = false;
- boolean hasPackageAccessibleType = false;
+ boolean hasVisibleToPackagesType = false;
for (AppSearchSchema schema : getSchemaResponse.getSchemas()) {
if (schema.getSchemaType().equals(VisibilityDocument.SCHEMA_TYPE)) {
hasVisibilityType = true;
- } else if (schema.getSchemaType().equals(PackageAccessibleDocument.SCHEMA_TYPE)) {
- hasPackageAccessibleType = true;
+ } else if (schema.getSchemaType().equals(VisibleToPackagesDocument.SCHEMA_TYPE)) {
+ hasVisibleToPackagesType = true;
}
- if (hasVisibilityType && hasPackageAccessibleType) {
+ if (hasVisibilityType && hasVisibleToPackagesType) {
// Found both our types, can exit early.
break;
}
}
- if (!hasVisibilityType || !hasPackageAccessibleType) {
+ if (!hasVisibilityType || !hasVisibleToPackagesType) {
// Schema type doesn't exist yet. Add it.
mAppSearchImpl.setSchema(
PACKAGE_NAME,
DATABASE_NAME,
- Arrays.asList(VisibilityDocument.SCHEMA, PackageAccessibleDocument.SCHEMA),
+ Arrays.asList(VisibilityDocument.SCHEMA, VisibleToPackagesDocument.SCHEMA),
/*visibilityStore=*/ null, // Avoid recursive calls
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ SCHEMA_VERSION);
}
@@ -177,26 +162,25 @@ public class VisibilityStore {
}
// Update platform visibility settings
- String[] notPlatformSurfaceableSchemas =
- visibilityDocument.getNotPlatformSurfaceableSchemas();
- if (notPlatformSurfaceableSchemas != null) {
- mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(
+ String[] notDisplayedBySystemSchemas = visibilityDocument.getNotDisplayedBySystem();
+ if (notDisplayedBySystemSchemas != null) {
+ mNotDisplayedBySystemMap.setNotDisplayedBySystem(
packageName,
databaseName,
- new ArraySet<>(notPlatformSurfaceableSchemas));
+ new ArraySet<>(notDisplayedBySystemSchemas));
}
// Update 3p package visibility settings
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>();
- GenericDocument[] packageAccessibleDocuments =
- visibilityDocument.getPackageAccessibleSchemas();
- if (packageAccessibleDocuments != null) {
- for (int i = 0; i < packageAccessibleDocuments.length; i++) {
- PackageAccessibleDocument packageAccessibleDocument =
- new PackageAccessibleDocument(packageAccessibleDocuments[i]);
+ GenericDocument[] visibleToPackagesDocuments =
+ visibilityDocument.getVisibleToPackages();
+ if (visibleToPackagesDocuments != null) {
+ for (int i = 0; i < visibleToPackagesDocuments.length; i++) {
+ VisibleToPackagesDocument visibleToPackagesDocument =
+ new VisibleToPackagesDocument(visibleToPackagesDocuments[i]);
PackageIdentifier packageIdentifier =
- packageAccessibleDocument.getPackageIdentifier();
- String prefixedSchema = packageAccessibleDocument.getAccessibleSchemaType();
+ visibleToPackagesDocument.getPackageIdentifier();
+ String prefixedSchema = visibleToPackagesDocument.getAccessibleSchemaType();
Set<PackageIdentifier> packageIdentifiers =
schemaToPackageIdentifierMap.get(prefixedSchema);
if (packageIdentifiers == null) {
@@ -206,61 +190,50 @@ public class VisibilityStore {
schemaToPackageIdentifierMap.put(prefixedSchema, packageIdentifiers);
}
}
- mPackageAccessibleMap.setPackageAccessible(
+ mVisibleToPackagesMap.setVisibleToPackages(
packageName, databaseName, schemaToPackageIdentifierMap);
}
}
}
- /**
- * Sets visibility settings for the given database. Any previous visibility settings will be
- * overwritten.
- *
- * @param packageName Package of app that owns the {@code schemasNotPlatformSurfaceable}.
- * @param databaseName Database that owns the {@code schemasNotPlatformSurfaceable}.
- * @param schemasNotPlatformSurfaceable Set of prefixed schemas that should be hidden from the
- * platform.
- * @param schemasPackageAccessible Map of prefixed schemas to a list of package identifiers that
- * have access to the schema.
- * @throws AppSearchException on AppSearchImpl error.
- */
+ @Override
public void setVisibility(
@NonNull String packageName,
@NonNull String databaseName,
- @NonNull Set<String> schemasNotPlatformSurfaceable,
- @NonNull Map<String, List<PackageIdentifier>> schemasPackageAccessible)
+ @NonNull Set<String> schemasNotDisplayedBySystem,
+ @NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages)
throws AppSearchException {
Objects.requireNonNull(packageName);
Objects.requireNonNull(databaseName);
- Objects.requireNonNull(schemasNotPlatformSurfaceable);
- Objects.requireNonNull(schemasPackageAccessible);
+ Objects.requireNonNull(schemasNotDisplayedBySystem);
+ Objects.requireNonNull(schemasVisibleToPackages);
// Persist the document
VisibilityDocument.Builder visibilityDocument =
new VisibilityDocument.Builder(
NAMESPACE, /*id=*/ getVisibilityDocumentId(packageName, databaseName));
- if (!schemasNotPlatformSurfaceable.isEmpty()) {
- visibilityDocument.setSchemasNotPlatformSurfaceable(
- schemasNotPlatformSurfaceable.toArray(new String[0]));
+ if (!schemasNotDisplayedBySystem.isEmpty()) {
+ visibilityDocument.setNotDisplayedBySystem(
+ schemasNotDisplayedBySystem.toArray(new String[0]));
}
Map<String, Set<PackageIdentifier>> schemaToPackageIdentifierMap = new ArrayMap<>();
- List<PackageAccessibleDocument> packageAccessibleDocuments = new ArrayList<>();
+ List<VisibleToPackagesDocument> visibleToPackagesDocuments = new ArrayList<>();
for (Map.Entry<String, List<PackageIdentifier>> entry :
- schemasPackageAccessible.entrySet()) {
+ schemasVisibleToPackages.entrySet()) {
for (int i = 0; i < entry.getValue().size(); i++) {
- PackageAccessibleDocument packageAccessibleDocument =
- new PackageAccessibleDocument.Builder(NAMESPACE, /*id=*/ "")
+ VisibleToPackagesDocument visibleToPackagesDocument =
+ new VisibleToPackagesDocument.Builder(NAMESPACE, /*id=*/ "")
.setAccessibleSchemaType(entry.getKey())
.setPackageIdentifier(entry.getValue().get(i))
.build();
- packageAccessibleDocuments.add(packageAccessibleDocument);
+ visibleToPackagesDocuments.add(visibleToPackagesDocument);
}
schemaToPackageIdentifierMap.put(entry.getKey(), new ArraySet<>(entry.getValue()));
}
- if (!packageAccessibleDocuments.isEmpty()) {
- visibilityDocument.setPackageAccessibleSchemas(
- packageAccessibleDocuments.toArray(new PackageAccessibleDocument[0]));
+ if (!visibleToPackagesDocuments.isEmpty()) {
+ visibilityDocument.setVisibleToPackages(
+ visibleToPackagesDocuments.toArray(new VisibleToPackagesDocument[0]));
}
mAppSearchImpl.putDocument(
@@ -269,9 +242,9 @@ public class VisibilityStore {
mAppSearchImpl.persistToDisk(PersistType.Code.LITE);
// Update derived data structures.
- mNotPlatformSurfaceableMap.setNotPlatformSurfaceable(
- packageName, databaseName, schemasNotPlatformSurfaceable);
- mPackageAccessibleMap.setPackageAccessible(
+ mNotDisplayedBySystemMap.setNotDisplayedBySystem(
+ packageName, databaseName, schemasNotDisplayedBySystem);
+ mVisibleToPackagesMap.setVisibleToPackages(
packageName, databaseName, schemaToPackageIdentifierMap);
}
@@ -287,17 +260,7 @@ public class VisibilityStore {
== PackageManager.PERMISSION_GRANTED;
}
- /**
- * Checks whether {@code prefixedSchema} can be searched over by the {@code callerUid}.
- *
- * @param packageName Package that owns the schema.
- * @param databaseName Database within the package that owns the schema.
- * @param prefixedSchema Prefixed schema type the caller is trying to access.
- * @param callerUid UID of the client making the globalQuery call.
- * @param callerHasSystemAccess Whether the caller has been identified as having
- * access to schemas marked system surfaceable by {@link
- * #doesCallerHaveSystemAccess}.
- */
+ @Override
public boolean isSchemaSearchableByCaller(
@NonNull String packageName,
@NonNull String databaseName,
@@ -313,13 +276,13 @@ public class VisibilityStore {
}
if (callerHasSystemAccess
- && mNotPlatformSurfaceableMap.isSchemaPlatformSurfaceable(
+ && mNotDisplayedBySystemMap.isSchemaDisplayedBySystem(
packageName, databaseName, prefixedSchema)) {
return true;
}
// May not be platform surfaceable, but might still be accessible through 3p access.
- return isSchemaPackageAccessible(packageName, databaseName, prefixedSchema, callerUid);
+ return isSchemaVisibleToPackages(packageName, databaseName, prefixedSchema, callerUid);
}
/**
@@ -331,13 +294,13 @@ public class VisibilityStore {
* certificate was once used to sign the package, the package will still be granted access. This
* does not handle packages that have been signed by multiple certificates.
*/
- private boolean isSchemaPackageAccessible(
+ private boolean isSchemaVisibleToPackages(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull String prefixedSchema,
int callerUid) {
Set<PackageIdentifier> packageIdentifiers =
- mPackageAccessibleMap.getAccessiblePackages(
+ mVisibleToPackagesMap.getAccessiblePackages(
packageName, databaseName, prefixedSchema);
if (packageIdentifiers.isEmpty()) {
return false;
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleDocument.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesDocument.java
index 0b4e196fd0c4..8d503390eaaa 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleDocument.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesDocument.java
@@ -26,7 +26,7 @@ import android.app.appsearch.PackageIdentifier;
*
* @see android.app.appsearch.SetSchemaRequest.Builder#setSchemaTypeVisibilityForPackage
*/
-class PackageAccessibleDocument extends GenericDocument {
+class VisibleToPackagesDocument extends GenericDocument {
/** Schema type for nested documents that hold package accessible information. */
public static final String SCHEMA_TYPE = "PackageAccessibleType";
@@ -59,7 +59,7 @@ class PackageAccessibleDocument extends GenericDocument {
.build())
.build();
- public PackageAccessibleDocument(@NonNull GenericDocument genericDocument) {
+ VisibleToPackagesDocument(@NonNull GenericDocument genericDocument) {
super(genericDocument);
}
@@ -76,9 +76,9 @@ class PackageAccessibleDocument extends GenericDocument {
return new PackageIdentifier(packageName, sha256Cert);
}
- /** Builder for {@link PackageAccessibleDocument} instances. */
- public static class Builder extends GenericDocument.Builder<PackageAccessibleDocument.Builder> {
- public Builder(@NonNull String namespace, @NonNull String id) {
+ /** Builder for {@link VisibleToPackagesDocument} instances. */
+ public static class Builder extends GenericDocument.Builder<VisibleToPackagesDocument.Builder> {
+ Builder(@NonNull String namespace, @NonNull String id) {
super(namespace, id, SCHEMA_TYPE);
}
@@ -98,8 +98,8 @@ class PackageAccessibleDocument extends GenericDocument {
@Override
@NonNull
- public PackageAccessibleDocument build() {
- return new PackageAccessibleDocument(super.build());
+ public VisibleToPackagesDocument build() {
+ return new VisibleToPackagesDocument(super.build());
}
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesMap.java
index cff729aa4e8a..e2b51a75025c 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/PackageAccessibleMap.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibleToPackagesMap.java
@@ -29,7 +29,7 @@ import java.util.Set;
*
* This object is not thread safe.
*/
-class PackageAccessibleMap {
+class VisibleToPackagesMap {
/**
* Maps packages to databases to prefixed schemas to PackageIdentifiers that have access to that
* schema.
@@ -42,7 +42,7 @@ class PackageAccessibleMap {
*
* <p>Any existing mappings for this prefix are overwritten.
*/
- public void setPackageAccessible(
+ public void setVisibleToPackages(
@NonNull String packageName,
@NonNull String databaseName,
@NonNull Map<String, Set<PackageIdentifier>> schemaToPackageIdentifier) {
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index 78d39cc6deac..65551074f9c0 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-31a54dba5bda4d0109ea91eb1ac047c937cbaae3
+c7387d9b58726a23a0608a9365fb3a1b57b7b8a1
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
index d6ce3ebc267f..7b74578adfc7 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchSessionShim.java
@@ -51,8 +51,6 @@ public interface AppSearchSessionShim extends Closeable {
* @param request the schema to set or update the AppSearch database to.
* @return a {@link ListenableFuture} which resolves to a {@link SetSchemaResponse} object.
*/
- // TODO(b/169883602): Change @code references to @link when setPlatformSurfaceable APIs are
- // exposed.
@NonNull
ListenableFuture<SetSchemaResponse> setSchema(@NonNull SetSchemaRequest request);
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 0e9efbcc98b8..ac2018707c75 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -442,6 +442,7 @@ public class DeviceIdleController extends SystemService
private long mNextIdlePendingDelay;
private long mNextIdleDelay;
private long mNextLightIdleDelay;
+ private long mNextLightIdleDelayFlex;
private long mNextLightAlarmTime;
private long mNextSensingTimeoutAlarmTime;
@@ -886,16 +887,20 @@ public class DeviceIdleController extends SystemService
*/
public final class Constants implements DeviceConfig.OnPropertiesChangedListener {
// Key names stored in the settings value.
- private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT
- = "light_after_inactive_to";
+ private static final String KEY_FLEX_TIME_SHORT = "flex_time_short";
+ private static final String KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
+ "light_after_inactive_to";
private static final String KEY_LIGHT_PRE_IDLE_TIMEOUT = "light_pre_idle_to";
private static final String KEY_LIGHT_IDLE_TIMEOUT = "light_idle_to";
+ private static final String KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
+ "light_idle_to_initial_flex";
+ private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX = "light_max_idle_to_flex";
private static final String KEY_LIGHT_IDLE_FACTOR = "light_idle_factor";
private static final String KEY_LIGHT_MAX_IDLE_TIMEOUT = "light_max_idle_to";
- private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET
- = "light_idle_maintenance_min_budget";
- private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET
- = "light_idle_maintenance_max_budget";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MIN_BUDGET =
+ "light_idle_maintenance_min_budget";
+ private static final String KEY_LIGHT_IDLE_MAINTENANCE_MAX_BUDGET =
+ "light_idle_maintenance_max_budget";
private static final String KEY_MIN_LIGHT_MAINTENANCE_TIME = "min_light_maintenance_time";
private static final String KEY_MIN_DEEP_MAINTENANCE_TIME = "min_deep_maintenance_time";
private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
@@ -903,6 +908,7 @@ public class DeviceIdleController extends SystemService
private static final String KEY_LOCATING_TIMEOUT = "locating_to";
private static final String KEY_LOCATION_ACCURACY = "location_accuracy";
private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
+ private static final String KEY_MOTION_INACTIVE_TIMEOUT_FLEX = "motion_inactive_to_flex";
private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
@@ -929,13 +935,20 @@ public class DeviceIdleController extends SystemService
"pre_idle_factor_long";
private static final String KEY_PRE_IDLE_FACTOR_SHORT =
"pre_idle_factor_short";
+ private static final String KEY_USE_WINDOW_ALARMS = "use_window_alarms";
+ private static final long DEFAULT_FLEX_TIME_SHORT =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT =
- !COMPRESS_TIME ? 3 * 60 * 1000L : 15 * 1000L;
+ !COMPRESS_TIME ? 60 * 1000L : 15 * 1000L;
private static final long DEFAULT_LIGHT_PRE_IDLE_TIMEOUT =
!COMPRESS_TIME ? 3 * 60 * 1000L : 30 * 1000L;
private static final long DEFAULT_LIGHT_IDLE_TIMEOUT =
!COMPRESS_TIME ? 5 * 60 * 1000L : 15 * 1000L;
+ private static final long DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
+ private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX =
+ !COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
private static final float DEFAULT_LIGHT_IDLE_FACTOR = 2f;
private static final long DEFAULT_LIGHT_MAX_IDLE_TIMEOUT =
!COMPRESS_TIME ? 15 * 60 * 1000L : 60 * 1000L;
@@ -958,6 +971,8 @@ public class DeviceIdleController extends SystemService
private static final float DEFAULT_LOCATION_ACCURACY = 20f;
private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT =
!COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L;
+ private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX =
+ !COMPRESS_TIME ? 60 * 1000L : 5 * 1000L;
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT =
(30 * 60 * 1000L) / (!COMPRESS_TIME ? 1 : 10);
private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY =
@@ -983,6 +998,14 @@ public class DeviceIdleController extends SystemService
private static final boolean DEFAULT_WAIT_FOR_UNLOCK = true;
private static final float DEFAULT_PRE_IDLE_FACTOR_LONG = 1.67f;
private static final float DEFAULT_PRE_IDLE_FACTOR_SHORT = .33f;
+ private static final boolean DEFAULT_USE_WINDOW_ALARMS = true;
+
+ /**
+ * A somewhat short alarm window size that we will tolerate for various alarm timings.
+ *
+ * @see #KEY_FLEX_TIME_SHORT
+ */
+ public long FLEX_TIME_SHORT = DEFAULT_FLEX_TIME_SHORT;
/**
* This is the time, after becoming inactive, that we go in to the first
@@ -1002,13 +1025,28 @@ public class DeviceIdleController extends SystemService
public long LIGHT_PRE_IDLE_TIMEOUT = DEFAULT_LIGHT_PRE_IDLE_TIMEOUT;
/**
- * This is the initial time that we will run in idle maintenance mode.
+ * This is the initial time that we will run in light idle maintenance mode.
*
* @see #KEY_LIGHT_IDLE_TIMEOUT
*/
public long LIGHT_IDLE_TIMEOUT = DEFAULT_LIGHT_IDLE_TIMEOUT;
/**
+ * This is the initial alarm window size that we will tolerate for light idle maintenance
+ * timing.
+ *
+ * @see #KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX
+ */
+ public long LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
+
+ /**
+ * This is the maximum value that {@link #LIGHT_IDLE_TIMEOUT_INITIAL_FLEX} should take.
+ *
+ * @see #KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX
+ */
+ public long LIGHT_MAX_IDLE_TIMEOUT_FLEX = DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX;
+
+ /**
* Scaling factor to apply to the light idle mode time each time we complete a cycle.
*
* @see #KEY_LIGHT_IDLE_FACTOR
@@ -1016,7 +1054,7 @@ public class DeviceIdleController extends SystemService
public float LIGHT_IDLE_FACTOR = DEFAULT_LIGHT_IDLE_FACTOR;
/**
- * This is the maximum time we will run in idle maintenance mode.
+ * This is the maximum time we will stay in light idle mode.
*
* @see #KEY_LIGHT_MAX_IDLE_TIMEOUT
*/
@@ -1099,13 +1137,22 @@ public class DeviceIdleController extends SystemService
/**
* This is the time, after seeing motion, that we wait after becoming inactive from
* that until we start looking for motion again.
+ *
* @see #KEY_MOTION_INACTIVE_TIMEOUT
*/
public long MOTION_INACTIVE_TIMEOUT = DEFAULT_MOTION_INACTIVE_TIMEOUT;
/**
+ * This is the alarm window size we will tolerate for motion detection timings.
+ *
+ * @see #KEY_MOTION_INACTIVE_TIMEOUT_FLEX
+ */
+ public long MOTION_INACTIVE_TIMEOUT_FLEX = DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX;
+
+ /**
* This is the time, after the inactive timeout elapses, that we will wait looking
* for motion until we truly consider the device to be idle.
+ *
* @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
*/
public long IDLE_AFTER_INACTIVE_TIMEOUT = DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT;
@@ -1204,6 +1251,12 @@ public class DeviceIdleController extends SystemService
public boolean WAIT_FOR_UNLOCK = DEFAULT_WAIT_FOR_UNLOCK;
+ /**
+ * Whether to use window alarms. True to use window alarms (call AlarmManager.setWindow()).
+ * False to use the legacy inexact alarms (call AlarmManager.set()).
+ */
+ public boolean USE_WINDOW_ALARMS = DEFAULT_USE_WINDOW_ALARMS;
+
private final boolean mSmallBatteryDevice;
public Constants() {
@@ -1227,6 +1280,10 @@ public class DeviceIdleController extends SystemService
continue;
}
switch (name) {
+ case KEY_FLEX_TIME_SHORT:
+ FLEX_TIME_SHORT = properties.getLong(
+ KEY_FLEX_TIME_SHORT, DEFAULT_FLEX_TIME_SHORT);
+ break;
case KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT:
LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
@@ -1240,9 +1297,19 @@ public class DeviceIdleController extends SystemService
LIGHT_IDLE_TIMEOUT = properties.getLong(
KEY_LIGHT_IDLE_TIMEOUT, DEFAULT_LIGHT_IDLE_TIMEOUT);
break;
+ case KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX:
+ LIGHT_IDLE_TIMEOUT_INITIAL_FLEX = properties.getLong(
+ KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX,
+ DEFAULT_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX);
+ break;
+ case KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX:
+ LIGHT_MAX_IDLE_TIMEOUT_FLEX = properties.getLong(
+ KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX,
+ DEFAULT_LIGHT_MAX_IDLE_TIMEOUT_FLEX);
+ break;
case KEY_LIGHT_IDLE_FACTOR:
- LIGHT_IDLE_FACTOR = properties.getFloat(
- KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR);
+ LIGHT_IDLE_FACTOR = Math.max(1, properties.getFloat(
+ KEY_LIGHT_IDLE_FACTOR, DEFAULT_LIGHT_IDLE_FACTOR));
break;
case KEY_LIGHT_MAX_IDLE_TIMEOUT:
LIGHT_MAX_IDLE_TIMEOUT = properties.getLong(
@@ -1291,6 +1358,11 @@ public class DeviceIdleController extends SystemService
MOTION_INACTIVE_TIMEOUT = properties.getLong(
KEY_MOTION_INACTIVE_TIMEOUT, DEFAULT_MOTION_INACTIVE_TIMEOUT);
break;
+ case KEY_MOTION_INACTIVE_TIMEOUT_FLEX:
+ MOTION_INACTIVE_TIMEOUT_FLEX = properties.getLong(
+ KEY_MOTION_INACTIVE_TIMEOUT_FLEX,
+ DEFAULT_MOTION_INACTIVE_TIMEOUT_FLEX);
+ break;
case KEY_IDLE_AFTER_INACTIVE_TIMEOUT:
final long defaultIdleAfterInactiveTimeout = mSmallBatteryDevice
? DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT_SMALL_BATTERY
@@ -1362,6 +1434,10 @@ public class DeviceIdleController extends SystemService
PRE_IDLE_FACTOR_SHORT = properties.getFloat(
KEY_PRE_IDLE_FACTOR_SHORT, DEFAULT_PRE_IDLE_FACTOR_SHORT);
break;
+ case KEY_USE_WINDOW_ALARMS:
+ USE_WINDOW_ALARMS = properties.getBoolean(
+ KEY_USE_WINDOW_ALARMS, DEFAULT_USE_WINDOW_ALARMS);
+ break;
default:
Slog.e(TAG, "Unknown configuration key: " + name);
break;
@@ -1373,6 +1449,10 @@ public class DeviceIdleController extends SystemService
void dump(PrintWriter pw) {
pw.println(" Settings:");
+ pw.print(" "); pw.print(KEY_FLEX_TIME_SHORT); pw.print("=");
+ TimeUtils.formatDuration(FLEX_TIME_SHORT, pw);
+ pw.println();
+
pw.print(" ");
pw.print(KEY_LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
pw.print("=");
@@ -1387,6 +1467,14 @@ public class DeviceIdleController extends SystemService
TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_LIGHT_IDLE_TIMEOUT_INITIAL_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_IDLE_TIMEOUT_INITIAL_FLEX, pw);
+ pw.println();
+
+ pw.print(" "); pw.print(KEY_LIGHT_MAX_IDLE_TIMEOUT_FLEX); pw.print("=");
+ TimeUtils.formatDuration(LIGHT_MAX_IDLE_TIMEOUT_FLEX, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_LIGHT_IDLE_FACTOR); pw.print("=");
pw.print(LIGHT_IDLE_FACTOR);
pw.println();
@@ -1431,6 +1519,10 @@ public class DeviceIdleController extends SystemService
TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
pw.println();
+ pw.print(" "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT_FLEX); pw.print("=");
+ TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT_FLEX, pw);
+ pw.println();
+
pw.print(" "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("=");
TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
pw.println();
@@ -1489,6 +1581,9 @@ public class DeviceIdleController extends SystemService
pw.print(" "); pw.print(KEY_PRE_IDLE_FACTOR_SHORT); pw.print("=");
pw.println(PRE_IDLE_FACTOR_SHORT);
+
+ pw.print(" "); pw.print(KEY_USE_WINDOW_ALARMS); pw.print("=");
+ pw.println(USE_WINDOW_ALARMS);
}
}
@@ -3199,7 +3294,8 @@ public class DeviceIdleController extends SystemService
mLightState = LIGHT_STATE_INACTIVE;
if (DEBUG) Slog.d(TAG, "Moved from LIGHT_STATE_ACTIVE to LIGHT_STATE_INACTIVE");
resetLightIdleManagementLocked();
- scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT);
+ scheduleLightAlarmLocked(mConstants.LIGHT_IDLE_AFTER_INACTIVE_TIMEOUT,
+ mConstants.FLEX_TIME_SHORT);
EventLogTags.writeDeviceIdleLight(mLightState, "no activity");
}
}
@@ -3219,6 +3315,7 @@ public class DeviceIdleController extends SystemService
private void resetLightIdleManagementLocked() {
mNextLightIdleDelay = 0;
+ mNextLightIdleDelayFlex = 0;
mCurLightIdleBudget = 0;
cancelLightAlarmLocked();
}
@@ -3265,13 +3362,15 @@ public class DeviceIdleController extends SystemService
mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET;
// Reset the upcoming idle delays.
mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
+ mNextLightIdleDelayFlex = mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX;
mMaintenanceStartTime = 0;
if (!isOpsInactiveLocked()) {
// We have some active ops going on... give them a chance to finish
// before going in to our first idle.
mLightState = LIGHT_STATE_PRE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
- scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT);
+ scheduleLightAlarmLocked(mConstants.LIGHT_PRE_IDLE_TIMEOUT,
+ mConstants.FLEX_TIME_SHORT);
break;
}
// Nothing active, fall through to immediately idle.
@@ -3290,12 +3389,11 @@ public class DeviceIdleController extends SystemService
}
}
mMaintenanceStartTime = 0;
- scheduleLightAlarmLocked(mNextLightIdleDelay);
+ scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex);
mNextLightIdleDelay = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT,
- (long)(mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
- if (mNextLightIdleDelay < mConstants.LIGHT_IDLE_TIMEOUT) {
- mNextLightIdleDelay = mConstants.LIGHT_IDLE_TIMEOUT;
- }
+ (long) (mNextLightIdleDelay * mConstants.LIGHT_IDLE_FACTOR));
+ mNextLightIdleDelayFlex = Math.min(mConstants.LIGHT_MAX_IDLE_TIMEOUT_FLEX,
+ (long) (mNextLightIdleDelayFlex * mConstants.LIGHT_IDLE_FACTOR));
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_STATE_IDLE.");
mLightState = LIGHT_STATE_IDLE;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
@@ -3315,7 +3413,7 @@ public class DeviceIdleController extends SystemService
} else if (mCurLightIdleBudget > mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET) {
mCurLightIdleBudget = mConstants.LIGHT_IDLE_MAINTENANCE_MAX_BUDGET;
}
- scheduleLightAlarmLocked(mCurLightIdleBudget);
+ scheduleLightAlarmLocked(mCurLightIdleBudget, mConstants.FLEX_TIME_SHORT);
if (DEBUG) Slog.d(TAG,
"Moved from LIGHT_STATE_IDLE to LIGHT_STATE_IDLE_MAINTENANCE.");
mLightState = LIGHT_STATE_IDLE_MAINTENANCE;
@@ -3326,7 +3424,7 @@ public class DeviceIdleController extends SystemService
// We'd like to do maintenance, but currently don't have network
// connectivity... let's try to wait until the network comes back.
// We'll only wait for another full idle period, however, and then give up.
- scheduleLightAlarmLocked(mNextLightIdleDelay);
+ scheduleLightAlarmLocked(mNextLightIdleDelay, mNextLightIdleDelayFlex / 2);
if (DEBUG) Slog.d(TAG, "Moved to LIGHT_WAITING_FOR_NETWORK.");
mLightState = LIGHT_STATE_WAITING_FOR_NETWORK;
EventLogTags.writeDeviceIdleLight(mLightState, reason);
@@ -3844,40 +3942,75 @@ public class DeviceIdleController extends SystemService
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mConstants.FLEX_TIME_SHORT,
+ mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ }
}
}
- void scheduleLightAlarmLocked(long delay) {
- if (DEBUG) Slog.d(TAG, "scheduleLightAlarmLocked(" + delay + ")");
+ void scheduleLightAlarmLocked(long delay, long flex) {
+ if (DEBUG) {
+ Slog.d(TAG, "scheduleLightAlarmLocked(" + delay
+ + (mConstants.USE_WINDOW_ALARMS ? "/" + flex : "") + ")");
+ }
mNextLightAlarmTime = SystemClock.elapsedRealtime() + delay;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
- mNextLightAlarmTime, "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime, flex,
+ "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextLightAlarmTime,
+ "DeviceIdleController.light", mLightAlarmListener, mHandler);
+ }
}
private void scheduleMotionRegistrationAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionRegistrationAlarmLocked");
long nextMotionRegistrationAlarmTime =
mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT / 2;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime,
- "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
- mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ nextMotionRegistrationAlarmTime, mConstants.MOTION_INACTIVE_TIMEOUT_FLEX,
+ "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
+ mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionRegistrationAlarmTime,
+ "DeviceIdleController.motion_registration", mMotionRegistrationAlarmListener,
+ mHandler);
+ }
}
private void scheduleMotionTimeoutAlarmLocked() {
if (DEBUG) Slog.d(TAG, "scheduleMotionAlarmLocked");
long nextMotionTimeoutAlarmTime =
mInjector.getElapsedRealtime() + mConstants.MOTION_INACTIVE_TIMEOUT;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime,
- "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ nextMotionTimeoutAlarmTime,
+ mConstants.MOTION_INACTIVE_TIMEOUT_FLEX,
+ "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextMotionTimeoutAlarmTime,
+ "DeviceIdleController.motion", mMotionTimeoutAlarmListener, mHandler);
+ }
}
void scheduleSensingTimeoutAlarmLocked(long delay) {
if (DEBUG) Slog.d(TAG, "scheduleSensingAlarmLocked(" + delay + ")");
mNextSensingTimeoutAlarmTime = SystemClock.elapsedRealtime() + delay;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime,
- "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ if (mConstants.USE_WINDOW_ALARMS) {
+ mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextSensingTimeoutAlarmTime,
+ mConstants.FLEX_TIME_SHORT,
+ "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ } else {
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNextSensingTimeoutAlarmTime,
+ "DeviceIdleController.sensing", mSensingTimeoutAlarmListener, mHandler);
+ }
}
private static int[] buildAppIdArray(ArrayMap<String, Integer> systemApps,
@@ -4852,7 +4985,13 @@ public class DeviceIdleController extends SystemService
if (mNextLightIdleDelay != 0) {
pw.print(" mNextIdleDelay=");
TimeUtils.formatDuration(mNextLightIdleDelay, pw);
- pw.println();
+ if (mConstants.USE_WINDOW_ALARMS) {
+ pw.print(" (flex=");
+ TimeUtils.formatDuration(mNextLightIdleDelayFlex, pw);
+ pw.println(")");
+ } else {
+ pw.println();
+ }
}
if (mNextLightAlarmTime != 0) {
pw.print(" mNextLightAlarmTime=");
diff --git a/api/Android.bp b/api/Android.bp
index a84e6a6cb031..2ea180ebf598 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -24,6 +24,41 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
+python_binary_host {
+ name: "api_versions_trimmer",
+ srcs: ["api_versions_trimmer.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: false,
+ },
+ },
+}
+
+python_test_host {
+ name: "api_versions_trimmer_unittests",
+ main: "api_versions_trimmer_unittests.py",
+ srcs: [
+ "api_versions_trimmer_unittests.py",
+ "api_versions_trimmer.py",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: false,
+ },
+ },
+}
+
metalava_cmd = "$(location metalava)"
// Silence reflection warnings. See b/168689341
metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
@@ -431,3 +466,41 @@ genrule {
},
],
}
+
+// This rule will filter classes present in the jar files of mainline modules
+// from the lint database in api-versions.xml.
+// This is done to reduce the number of false positive NewApi findings in
+// java libraries that compile against the module SDK
+genrule {
+ name: "api-versions-xml-public-filtered",
+ srcs: [
+ // Note: order matters: first parameter is the full api-versions.xml
+ // after that the stubs files in any order
+ // stubs files are all modules that export API surfaces EXCEPT ART
+ ":framework-doc-stubs{.api_versions.xml}",
+ ":android.net.ipsec.ike.stubs{.jar}",
+ ":conscrypt.module.public.api.stubs{.jar}",
+ ":framework-appsearch.stubs{.jar}",
+ ":framework-connectivity.stubs{.jar}",
+ ":framework-graphics.stubs{.jar}",
+ ":framework-media.stubs{.jar}",
+ ":framework-mediaprovider.stubs{.jar}",
+ ":framework-permission.stubs{.jar}",
+ ":framework-permission-s.stubs{.jar}",
+ ":framework-scheduling.stubs{.jar}",
+ ":framework-sdkextensions.stubs{.jar}",
+ ":framework-statsd.stubs{.jar}",
+ ":framework-tethering.stubs{.jar}",
+ ":framework-wifi.stubs{.jar}",
+ ":i18n.module.public.api.stubs{.jar}",
+ ],
+ out: ["api-versions-public-filtered.xml"],
+ tools: ["api_versions_trimmer"],
+ cmd: "$(location api_versions_trimmer) $(out) $(in)",
+ dist: {
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
+ },
+}
diff --git a/api/api_versions_trimmer.py b/api/api_versions_trimmer.py
new file mode 100755
index 000000000000..9afd95a3003a
--- /dev/null
+++ b/api/api_versions_trimmer.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Script to remove mainline APIs from the api-versions.xml."""
+
+import argparse
+import re
+import xml.etree.ElementTree as ET
+import zipfile
+
+
+def read_classes(stubs):
+ """Read classes from the stubs file.
+
+ Args:
+ stubs: argument can be a path to a file (a string), a file-like object or a
+ path-like object
+
+ Returns:
+ a set of the classes found in the file (set of strings)
+ """
+ classes = set()
+ with zipfile.ZipFile(stubs) as z:
+ for info in z.infolist():
+ if (not info.is_dir()
+ and info.filename.endswith(".class")
+ and not info.filename.startswith("META-INF")):
+ # drop ".class" extension
+ classes.add(info.filename[:-6])
+ return classes
+
+
+def filter_method_tag(method, classes_to_remove):
+ """Updates the signature of this method by calling filter_method_signature.
+
+ Updates the method passed into this function.
+
+ Args:
+ method: xml element that represents a method
+ classes_to_remove: set of classes you to remove
+ """
+ filtered = filter_method_signature(method.get("name"), classes_to_remove)
+ method.set("name", filtered)
+
+
+def filter_method_signature(signature, classes_to_remove):
+ """Removes mentions of certain classes from this method signature.
+
+ Replaces any existing classes that need to be removed, with java/lang/Object
+
+ Args:
+ signature: string that is a java representation of a method signature
+ classes_to_remove: set of classes you to remove
+ """
+ regex = re.compile("L.*?;")
+ start = signature.find("(")
+ matches = set(regex.findall(signature[start:]))
+ for m in matches:
+ # m[1:-1] to drop the leading `L` and `;` ending
+ if m[1:-1] in classes_to_remove:
+ signature = signature.replace(m, "Ljava/lang/Object;")
+ return signature
+
+
+def filter_lint_database(database, classes_to_remove, output):
+ """Reads a lint database and writes a filtered version without some classes.
+
+ Reads database from api-versions.xml and removes any references to classes
+ in the second argument. Writes the result (another xml with the same format
+ of the database) to output.
+
+ Args:
+ database: path to xml with lint database to read
+ classes_to_remove: iterable (ideally a set or similar for quick
+ lookups) that enumerates the classes that should be removed
+ output: path to write the filtered database
+ """
+ xml = ET.parse(database)
+ root = xml.getroot()
+ for c in xml.findall("class"):
+ cname = c.get("name")
+ if cname in classes_to_remove:
+ root.remove(c)
+ else:
+ # find the <extends /> tag inside this class to see if the parent
+ # has been removed from the known classes (attribute called name)
+ super_classes = c.findall("extends")
+ for super_class in super_classes:
+ super_class_name = super_class.get("name")
+ if super_class_name in classes_to_remove:
+ super_class.set("name", "java/lang/Object")
+ interfaces = c.findall("implements")
+ for interface in interfaces:
+ interface_name = interface.get("name")
+ if interface_name in classes_to_remove:
+ c.remove(interface)
+ for method in c.findall("method"):
+ filter_method_tag(method, classes_to_remove)
+ xml.write(output)
+
+
+def main():
+ """Run the program."""
+ parser = argparse.ArgumentParser(
+ description=
+ ("Read a lint database (api-versions.xml) and many stubs jar files. "
+ "Produce another database file that doesn't include the classes present "
+ "in the stubs file(s)."))
+ parser.add_argument("output", help="Destination of the result (xml file).")
+ parser.add_argument(
+ "api_versions",
+ help="The lint database (api-versions.xml file) to read data from"
+ )
+ parser.add_argument("stubs", nargs="+", help="The stubs jar file(s)")
+ parsed = parser.parse_args()
+ classes = set()
+ for stub in parsed.stubs:
+ classes.update(read_classes(stub))
+ filter_lint_database(parsed.api_versions, classes, parsed.output)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py
new file mode 100644
index 000000000000..4eb929ea1b5d
--- /dev/null
+++ b/api/api_versions_trimmer_unittests.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import io
+import re
+import unittest
+import xml.etree.ElementTree as ET
+import zipfile
+
+import api_versions_trimmer
+
+
+def create_in_memory_zip_file(files):
+ f = io.BytesIO()
+ with zipfile.ZipFile(f, "w") as z:
+ for fname in files:
+ with z.open(fname, mode="w") as class_file:
+ class_file.write(b"")
+ return f
+
+
+def indent(elem, level=0):
+ i = "\n" + level * " "
+ j = "\n" + (level - 1) * " "
+ if len(elem):
+ if not elem.text or not elem.text.strip():
+ elem.text = i + " "
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = i
+ for subelem in elem:
+ indent(subelem, level + 1)
+ if not elem.tail or not elem.tail.strip():
+ elem.tail = j
+ else:
+ if level and (not elem.tail or not elem.tail.strip()):
+ elem.tail = j
+ return elem
+
+
+def pretty_print(s):
+ tree = ET.parse(io.StringIO(s))
+ el = indent(tree.getroot())
+ res = ET.tostring(el).decode("utf-8")
+ # remove empty lines inside the result because this still breaks some
+ # comparisons
+ return re.sub(r"\n\s*\n", "\n", res, re.MULTILINE)
+
+
+class ApiVersionsTrimmerUnittests(unittest.TestCase):
+
+ def setUp(self):
+ # so it prints diffs in long strings (xml files)
+ self.maxDiff = None
+
+ def test_read_classes(self):
+ f = create_in_memory_zip_file(
+ ["a/b/C.class",
+ "a/b/D.class",
+ ]
+ )
+ res = api_versions_trimmer.read_classes(f)
+ self.assertEqual({"a/b/C", "a/b/D"}, res)
+
+ def test_read_classes_ignore_dex(self):
+ f = create_in_memory_zip_file(
+ ["a/b/C.class",
+ "a/b/D.class",
+ "a/b/E.dex",
+ "f.dex",
+ ]
+ )
+ res = api_versions_trimmer.read_classes(f)
+ self.assertEqual({"a/b/C", "a/b/D"}, res)
+
+ def test_read_classes_ignore_manifest(self):
+ f = create_in_memory_zip_file(
+ ["a/b/C.class",
+ "a/b/D.class",
+ "META-INFO/G.class"
+ ]
+ )
+ res = api_versions_trimmer.read_classes(f)
+ self.assertEqual({"a/b/C", "a/b/D"}, res)
+
+ def test_filter_method_signature(self):
+ xml = """
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
+ """
+ method = ET.fromstring(xml)
+ classes_to_remove = {"android/accessibilityservice/GestureDescription"}
+ expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
+ api_versions_trimmer.filter_method_tag(method, classes_to_remove)
+ self.assertEqual(expected, method.get("name"))
+
+ def test_filter_method_signature_with_L_in_method(self):
+ xml = """
+ <method name="dispatchLeftGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
+ """
+ method = ET.fromstring(xml)
+ classes_to_remove = {"android/accessibilityservice/GestureDescription"}
+ expected = "dispatchLeftGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
+ api_versions_trimmer.filter_method_tag(method, classes_to_remove)
+ self.assertEqual(expected, method.get("name"))
+
+ def test_filter_method_signature_with_L_in_class(self):
+ xml = """
+ <method name="dispatchGesture(Landroid/accessibilityservice/LeftGestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
+ """
+ method = ET.fromstring(xml)
+ classes_to_remove = {"android/accessibilityservice/LeftGestureDescription"}
+ expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
+ api_versions_trimmer.filter_method_tag(method, classes_to_remove)
+ self.assertEqual(expected, method.get("name"))
+
+ def test_filter_method_signature_with_inner_class(self):
+ xml = """
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription$Inner;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
+ """
+ method = ET.fromstring(xml)
+ classes_to_remove = {"android/accessibilityservice/GestureDescription$Inner"}
+ expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
+ api_versions_trimmer.filter_method_tag(method, classes_to_remove)
+ self.assertEqual(expected, method.get("name"))
+
+ def _run_filter_db_test(self, database_str, expected):
+ """Performs the pattern of testing the filter_lint_database method.
+
+ Filters instances of the class "a/b/C" (hard-coded) from the database string
+ and compares the result with the expected result (performs formatting of
+ the xml of both inputs)
+
+ Args:
+ database_str: string, the contents of the lint database (api-versions.xml)
+ expected: string, the expected result after filtering the original
+ database
+ """
+ database = io.StringIO(database_str)
+ classes_to_remove = {"a/b/C"}
+ output = io.BytesIO()
+ api_versions_trimmer.filter_lint_database(
+ database,
+ classes_to_remove,
+ output
+ )
+ expected = pretty_print(expected)
+ res = pretty_print(output.getvalue().decode("utf-8"))
+ self.assertEqual(expected, res)
+
+ def test_filter_lint_database_updates_method_signature_params(self):
+ self._run_filter_db_test(
+ database_str="""
+ <api version="2">
+ <!-- will be removed -->
+ <class name="a/b/C" since="1">
+ <extends name="java/lang/Object"/>
+ </class>
+
+ <class name="a/b/E" since="1">
+ <!-- extends will be modified -->
+ <extends name="a/b/C"/>
+ <!-- first parameter will be modified -->
+ <method name="dispatchGesture(La/b/C;Landroid/os/Handler;)Z" since="24"/>
+ <!-- second should remain untouched -->
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """,
+ expected="""
+ <api version="2">
+ <class name="a/b/E" since="1">
+ <extends name="java/lang/Object"/>
+ <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """)
+
+ def test_filter_lint_database_updates_method_signature_return(self):
+ self._run_filter_db_test(
+ database_str="""
+ <api version="2">
+ <!-- will be removed -->
+ <class name="a/b/C" since="1">
+ <extends name="java/lang/Object"/>
+ </class>
+
+ <class name="a/b/E" since="1">
+ <!-- extends will be modified -->
+ <extends name="a/b/C"/>
+ <!-- return type should be changed -->
+ <method name="gestureIdToString(I)La/b/C;" since="24"/>
+ </class>
+ </api>
+ """,
+ expected="""
+ <api version="2">
+ <class name="a/b/E" since="1">
+
+ <extends name="java/lang/Object"/>
+
+ <method name="gestureIdToString(I)Ljava/lang/Object;" since="24"/>
+ </class>
+ </api>
+ """)
+
+ def test_filter_lint_database_removes_implements(self):
+ self._run_filter_db_test(
+ database_str="""
+ <api version="2">
+ <!-- will be removed -->
+ <class name="a/b/C" since="1">
+ <extends name="java/lang/Object"/>
+ </class>
+
+ <class name="a/b/D" since="1">
+ <extends name="java/lang/Object"/>
+ <implements name="a/b/C"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """,
+ expected="""
+ <api version="2">
+
+ <class name="a/b/D" since="1">
+ <extends name="java/lang/Object"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """)
+
+ def test_filter_lint_database_updates_extends(self):
+ self._run_filter_db_test(
+ database_str="""
+ <api version="2">
+ <!-- will be removed -->
+ <class name="a/b/C" since="1">
+ <extends name="java/lang/Object"/>
+ </class>
+
+ <class name="a/b/E" since="1">
+ <!-- extends will be modified -->
+ <extends name="a/b/C"/>
+ <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """,
+ expected="""
+ <api version="2">
+ <class name="a/b/E" since="1">
+ <extends name="java/lang/Object"/>
+ <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """)
+
+ def test_filter_lint_database_removes_class(self):
+ self._run_filter_db_test(
+ database_str="""
+ <api version="2">
+ <!-- will be removed -->
+ <class name="a/b/C" since="1">
+ <extends name="java/lang/Object"/>
+ </class>
+
+ <class name="a/b/D" since="1">
+ <extends name="java/lang/Object"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """,
+ expected="""
+ <api version="2">
+
+ <class name="a/b/D" since="1">
+ <extends name="java/lang/Object"/>
+ <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
+sultCallback;Landroid/os/Handler;)Z" since="24"/>
+ </class>
+ </api>
+ """)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 96d59b80b479..9bd6c750fb13 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -4804,6 +4804,16 @@ public class AppOpsManager {
public static final int HISTORY_FLAG_DISCRETE = 1 << 1;
/**
+ * Flag for querying app op history: assemble attribution chains, and attach the last visible
+ * node in the chain to the start as a proxy info. This only applies to discrete accesses.
+ *
+ * TODO 191512294: Add to @SystemApi
+ *
+ * @hide
+ */
+ public static final int HISTORY_FLAG_GET_ATTRIBUTION_CHAINS = 1 << 2;
+
+ /**
* Flag for querying app op history: get all types of historical access information.
*
* @see #getHistoricalOps(HistoricalOpsRequest, Executor, Consumer)
@@ -4819,7 +4829,8 @@ public class AppOpsManager {
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "HISTORY_FLAG_" }, value = {
HISTORY_FLAG_AGGREGATE,
- HISTORY_FLAG_DISCRETE
+ HISTORY_FLAG_DISCRETE,
+ HISTORY_FLAG_GET_ATTRIBUTION_CHAINS
})
public @interface OpHistoryFlags {}
@@ -5037,7 +5048,8 @@ public class AppOpsManager {
* @return This builder.
*/
public @NonNull Builder setHistoryFlags(@OpHistoryFlags int flags) {
- Preconditions.checkFlagsArgument(flags, HISTORY_FLAGS_ALL);
+ Preconditions.checkFlagsArgument(flags,
+ HISTORY_FLAGS_ALL | HISTORY_FLAG_GET_ATTRIBUTION_CHAINS);
mHistoryFlags = flags;
return this;
}
@@ -5290,8 +5302,17 @@ public class AppOpsManager {
@Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
long discreteAccessTime, long discreteAccessDuration) {
getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
- uidState, opFlag, discreteAccessTime, discreteAccessDuration);
- };
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, null);
+ }
+
+ /** @hide */
+ public void addDiscreteAccess(int opCode, int uid, @NonNull String packageName,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int opFlag,
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
+ getOrCreateHistoricalUidOps(uid).addDiscreteAccess(opCode, packageName, attributionTag,
+ uidState, opFlag, discreteAccessTime, discreteAccessDuration, proxy);
+ }
/** @hide */
@@ -5623,9 +5644,10 @@ public class AppOpsManager {
private void addDiscreteAccess(int opCode, @NonNull String packageName,
@Nullable String attributionTag, @UidState int uidState,
- @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration) {
+ @OpFlags int flag, long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalPackageOps(packageName).addDiscreteAccess(opCode, attributionTag,
- uidState, flag, discreteAccessTime, discreteAccessDuration);
+ uidState, flag, discreteAccessTime, discreteAccessDuration, proxy);
};
/**
@@ -5889,9 +5911,9 @@ public class AppOpsManager {
private void addDiscreteAccess(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flag, long discreteAccessTime,
- long discreteAccessDuration) {
+ long discreteAccessDuration, @Nullable OpEventProxyInfo proxy) {
getOrCreateAttributedHistoricalOps(attributionTag).addDiscreteAccess(opCode, uidState,
- flag, discreteAccessTime, discreteAccessDuration);
+ flag, discreteAccessTime, discreteAccessDuration, proxy);
}
/**
@@ -6212,9 +6234,10 @@ public class AppOpsManager {
}
private void addDiscreteAccess(int opCode, @UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
getOrCreateHistoricalOp(opCode).addDiscreteAccess(uidState,flag, discreteAccessTime,
- discreteAccessDuration);
+ discreteAccessDuration, proxy);
}
/**
@@ -6583,11 +6606,12 @@ public class AppOpsManager {
}
private void addDiscreteAccess(@UidState int uidState, @OpFlags int flag,
- long discreteAccessTime, long discreteAccessDuration) {
+ long discreteAccessTime, long discreteAccessDuration,
+ @Nullable OpEventProxyInfo proxy) {
List<AttributedOpEntry> discreteAccesses = getOrCreateDiscreteAccesses();
LongSparseArray<NoteOpEvent> accessEvents = new LongSparseArray<>();
long key = makeKey(uidState, flag);
- NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, null);
+ NoteOpEvent note = new NoteOpEvent(discreteAccessTime, discreteAccessDuration, proxy);
accessEvents.append(key, note);
AttributedOpEntry access = new AttributedOpEntry(mOp, false, accessEvents, null);
int insertionPoint = discreteAccesses.size() - 1;
@@ -10022,6 +10046,8 @@ public class AppOpsManager {
NoteOpEvent existingAccess = accessEvents.get(key);
if (existingAccess == null || existingAccess.getDuration() == -1) {
accessEvents.append(key, access);
+ } else if (existingAccess.mProxy == null && access.mProxy != null ) {
+ existingAccess.mProxy = access.mProxy;
}
}
if (reject != null) {
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9ed76c1c13d1..a2c9795204ad 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -546,6 +546,10 @@ public final class LoadedApk {
if (aInfo.sharedLibraryFiles != null) {
int index = 0;
for (String lib : aInfo.sharedLibraryFiles) {
+ // sharedLibraryFiles might contain native shared libraries that are not APK paths.
+ if (!lib.endsWith(".apk")) {
+ continue;
+ }
if (!outSeenPaths.contains(lib) && !outZipPaths.contains(lib)) {
outZipPaths.add(index, lib);
index++;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ba0bc555eb57..506dfe09f3fa 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5606,14 +5606,24 @@ public class Notification implements Parcelable
final boolean snoozeEnabled = !hideSnoozeButton
&& mContext.getContentResolver() != null
- && (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1);
+ && isSnoozeSettingEnabled();
if (snoozeEnabled) {
big.setViewLayoutMarginDimen(R.id.notification_action_list_margin_target,
RemoteViews.MARGIN_BOTTOM, 0);
}
}
+ private boolean isSnoozeSettingEnabled() {
+ try {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.SHOW_NOTIFICATION_SNOOZE, 0) == 1;
+ } catch (SecurityException ex) {
+ // Most 3p apps can't access this snooze setting, so their NotificationListeners
+ // would be unable to create notification views if we propagated this exception.
+ return false;
+ }
+ }
+
/**
* Returns the actions that are not contextual.
*/
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index cd82deb13e9b..7ef0a19ec44c 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -111,12 +111,15 @@ public final class WallpaperColors implements Parcelable {
public WallpaperColors(Parcel parcel) {
mMainColors = new ArrayList<>();
mAllColors = new HashMap<>();
- final int count = parcel.readInt();
+ int count = parcel.readInt();
for (int i = 0; i < count; i++) {
final int colorInt = parcel.readInt();
Color color = Color.valueOf(colorInt);
mMainColors.add(color);
-
+ }
+ count = parcel.readInt();
+ for (int i = 0; i < count; i++) {
+ final int colorInt = parcel.readInt();
final int population = parcel.readInt();
mAllColors.put(colorInt, population);
}
@@ -411,9 +414,16 @@ public final class WallpaperColors implements Parcelable {
for (int i = 0; i < count; i++) {
Color color = mainColors.get(i);
dest.writeInt(color.toArgb());
- Integer population = mAllColors.get(color.toArgb());
- int populationInt = (population != null) ? population : 0;
- dest.writeInt(populationInt);
+ }
+ count = mAllColors.size();
+ dest.writeInt(count);
+ for (Map.Entry<Integer, Integer> colorEntry : mAllColors.entrySet()) {
+ if (colorEntry.getKey() != null) {
+ dest.writeInt(colorEntry.getKey());
+ Integer population = colorEntry.getValue();
+ int populationInt = (population != null) ? population : 0;
+ dest.writeInt(populationInt);
+ }
}
dest.writeInt(mColorHints);
}
@@ -476,12 +486,13 @@ public final class WallpaperColors implements Parcelable {
WallpaperColors other = (WallpaperColors) o;
return mMainColors.equals(other.mMainColors)
+ && mAllColors.equals(other.mAllColors)
&& mColorHints == other.mColorHints;
}
@Override
public int hashCode() {
- return 31 * mMainColors.hashCode() + mColorHints;
+ return (31 * mMainColors.hashCode() * mAllColors.hashCode()) + mColorHints;
}
/**
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index eb4c624be0b2..585eb61b6f57 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -68,5 +68,5 @@ interface IUsageStatsManager {
void reportUserInteraction(String packageName, int userId);
int getUsageSource();
void forceUsageSourceSettingRead();
- long getLastTimeAnyComponentUsed(String packageName);
+ long getLastTimeAnyComponentUsed(String packageName, String callingPackage);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index e8175c709d85..ac7a31874682 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -1287,7 +1287,7 @@ public final class UsageStatsManager {
android.Manifest.permission.PACKAGE_USAGE_STATS})
public long getLastTimeAnyComponentUsed(@NonNull String packageName) {
try {
- return mService.getLastTimeAnyComponentUsed(packageName);
+ return mService.getLastTimeAnyComponentUsed(packageName, mContext.getOpPackageName());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ded5e6e27a68..5b72b76c3578 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3054,6 +3054,9 @@ public final class BluetoothAdapter {
return true;
}
return false;
+ } else if (profile == BluetoothProfile.LE_AUDIO) {
+ BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
+ return true;
} else {
return false;
}
@@ -3142,6 +3145,10 @@ public final class BluetoothAdapter {
case BluetoothProfile.HEARING_AID:
BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
hearingAid.close();
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
+ leAudio.close();
}
}
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index b0ce6a55e9ba..12911d6e1232 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -62,6 +62,8 @@ interface IPackageInstaller {
void bypassNextStagedInstallerCheck(boolean value);
+ void bypassNextAllowedApexUpdateCheck(boolean value);
+
void setAllowUnlimitedSilentUpdates(String installerPackageName);
void setSilentUpdatesThrottleTime(long throttleTimeInSeconds);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c2ac80e7c98f..d3ed00608324 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -586,11 +586,6 @@ interface IPackageManager {
String targetCompilerFilter, boolean force);
/**
- * Ask the package manager to compile layouts in the given package.
- */
- boolean compileLayouts(String packageName);
-
- /**
* Ask the package manager to dump profiles associated with a package.
*/
void dumpProfiles(String packageName);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 33a34be1b968..2ed00b5d2982 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1278,6 +1278,13 @@ public abstract class PackageManager {
*/
public static final int INSTALL_STAGED = 0x00200000;
+ /**
+ * Flag parameter for {@link #installPackage} to indicate that check whether given APEX can be
+ * updated should be disabled for this install.
+ * @hide
+ */
+ public static final int INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK = 0x00400000;
+
/** @hide */
@IntDef(flag = true, value = {
DONT_KILL_APP,
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 4c44ba1fc9ef..5a7f21040d0a 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -1164,7 +1164,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
dest.writeTypedList(this.usesPermissions);
sForInternedStringList.parcel(this.implicitPermissions, dest, flags);
sForStringSet.parcel(this.upgradeKeySets, dest, flags);
- dest.writeMap(this.keySetMapping);
+ ParsingPackageUtils.writeKeySetMapping(dest, this.keySetMapping);
sForInternedStringList.parcel(this.protectedBroadcasts, dest, flags);
dest.writeTypedList(this.activities);
dest.writeTypedList(this.receivers);
@@ -1180,7 +1180,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
sForInternedString.parcel(this.volumeUuid, dest, flags);
dest.writeParcelable(this.signingDetails, flags);
dest.writeString(this.mPath);
- dest.writeParcelableList(this.queriesIntents, flags);
+ dest.writeTypedList(this.queriesIntents, flags);
sForInternedStringList.parcel(this.queriesPackages, dest, flags);
sForInternedStringSet.parcel(this.queriesProviders, dest, flags);
dest.writeString(this.appComponentFactory);
@@ -1287,7 +1287,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.usesPermissions = in.createTypedArrayList(ParsedUsesPermission.CREATOR);
this.implicitPermissions = sForInternedStringList.unparcel(in);
this.upgradeKeySets = sForStringSet.unparcel(in);
- this.keySetMapping = in.readHashMap(boot);
+ this.keySetMapping = ParsingPackageUtils.readKeySetMapping(in);
this.protectedBroadcasts = sForInternedStringList.unparcel(in);
this.activities = in.createTypedArrayList(ParsedActivity.CREATOR);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 6fd533355aad..dce242c9d87c 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -87,6 +87,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.Parcel;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
@@ -3160,6 +3161,68 @@ public class ParsingPackageUtils {
}
/**
+ * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
+ */
+ public static void writeKeySetMapping(@NonNull Parcel dest,
+ @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) {
+ if (keySetMapping == null) {
+ dest.writeInt(-1);
+ return;
+ }
+
+ final int N = keySetMapping.size();
+ dest.writeInt(N);
+
+ for (String key : keySetMapping.keySet()) {
+ dest.writeString(key);
+ ArraySet<PublicKey> keys = keySetMapping.get(key);
+ if (keys == null) {
+ dest.writeInt(-1);
+ continue;
+ }
+
+ final int M = keys.size();
+ dest.writeInt(M);
+ for (int j = 0; j < M; j++) {
+ dest.writeSerializable(keys.valueAt(j));
+ }
+ }
+ }
+
+ /**
+ * Reads a keyset mapping from the given parcel at the given data position. May return
+ * {@code null} if the serialized mapping was {@code null}.
+ */
+ @NonNull
+ public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) {
+ final int N = in.readInt();
+ if (N == -1) {
+ return null;
+ }
+
+ ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
+ for (int i = 0; i < N; ++i) {
+ String key = in.readString();
+ final int M = in.readInt();
+ if (M == -1) {
+ keySetMapping.put(key, null);
+ continue;
+ }
+
+ ArraySet<PublicKey> keys = new ArraySet<>(M);
+ for (int j = 0; j < M; ++j) {
+ PublicKey pk = (PublicKey) in.readSerializable();
+ keys.add(pk);
+ }
+
+ keySetMapping.put(key, keys);
+ }
+
+ return keySetMapping;
+ }
+
+
+ /**
* Callback interface for retrieving information that may be needed while parsing
* a package.
*/
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/core/java/android/content/pm/parsing/component/ParsedComponent.java
index 4aed77ae641b..9d830ec7a227 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponent.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponent.java
@@ -172,7 +172,7 @@ public abstract class ParsedComponent implements Parcelable {
this.packageName = sForInternedString.unparcel(in);
this.intents = sForIntentInfos.unparcel(in);
this.metaData = in.readBundle(boot);
- this.mProperties = in.createTypedArrayMap(Property.CREATOR);
+ this.mProperties = in.readHashMap(boot);
}
@NonNull
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 37469e916eef..08f5a8a582db 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -848,8 +848,10 @@ public final class Sensor {
/**
* Get the highest supported direct report mode rate level of the sensor.
*
- * @return Highest direct report rate level of this sensor. If the sensor does not support
- * direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}.
+ * @return Highest direct report rate level of this sensor. Note that if the app does not have
+ * the {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission, the highest
+ * direct report rate level is {@link SensorDirectChannel#RATE_NORMAL}. If the sensor
+ * does not support direct report mode, this returns {@link SensorDirectChannel#RATE_STOP}.
* @see SensorDirectChannel#RATE_STOP
* @see SensorDirectChannel#RATE_NORMAL
* @see SensorDirectChannel#RATE_FAST
@@ -1002,9 +1004,11 @@ public final class Sensor {
}
/**
- * @return the minimum delay allowed between two events in microsecond
+ * @return the minimum delay allowed between two events in microseconds
* or zero if this sensor only returns a value when the data it's measuring
- * changes.
+ * changes. Note that if the app does not have the
+ * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission, the
+ * minimum delay is capped at 5000 microseconds (200 Hz).
*/
public int getMinDelay() {
return mMinDelay;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 713b66abed21..572a8a81883a 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -46,6 +46,13 @@ import java.util.List;
* at {@link TriggerEventListener}. {@link Sensor#TYPE_SIGNIFICANT_MOTION}
* is an example of a trigger sensor.
* </p>
+ * <p>
+ * In order to access sensor data at high sampling rates (i.e. greater than 200 Hz
+ * for {@link SensorEventListener} and greater than {@link SensorDirectChannel#RATE_NORMAL}
+ * for {@link SensorDirectChannel}), apps must declare
+ * the {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS} permission
+ * in their AndroidManifest.xml file.
+ * </p>
* <pre class="prettyprint">
* public class SensorActivity extends Activity implements SensorEventListener {
* private final SensorManager mSensorManager;
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 2d46a4073809..e665d0fcc836 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -208,7 +208,8 @@ public interface BiometricFingerprintConstants {
FINGERPRINT_ACQUIRED_TOO_FAST,
FINGERPRINT_ACQUIRED_VENDOR,
FINGERPRINT_ACQUIRED_START,
- FINGERPRINT_ACQUIRED_UNKNOWN})
+ FINGERPRINT_ACQUIRED_UNKNOWN,
+ FINGERPRINT_ACQUIRED_IMMOBILE})
@Retention(RetentionPolicy.SOURCE)
@interface FingerprintAcquired {}
@@ -278,6 +279,14 @@ public interface BiometricFingerprintConstants {
int FINGERPRINT_ACQUIRED_UNKNOWN = 8;
/**
+ * This message may be sent during enrollment if the same area of the finger has already
+ * been captured during this enrollment session. In general, enrolling multiple areas of the
+ * same finger can help against false rejections.
+ * @hide
+ */
+ int FINGERPRINT_ACQUIRED_IMMOBILE = 9;
+
+ /**
* @hide
*/
int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index e24332a1885a..5b259f71feda 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -212,9 +212,9 @@ public final class CameraExtensionCharacteristics {
*/
private static final class CameraExtensionManagerGlobal {
private static final String TAG = "CameraExtensionManagerGlobal";
- private static final String PROXY_PACKAGE_NAME = "com.android.camera";
+ private static final String PROXY_PACKAGE_NAME = "com.android.cameraextensions";
private static final String PROXY_SERVICE_NAME =
- "com.android.camera.CameraExtensionsProxyService";
+ "com.android.cameraextensions.CameraExtensionsProxyService";
// Singleton instance
private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index a39bc4e0bee5..1c0ae281d9fe 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -16,6 +16,7 @@
package android.hardware.display;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.graphics.Point;
import android.hardware.SensorManager;
@@ -29,6 +30,9 @@ import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Objects;
/**
@@ -37,6 +41,16 @@ import java.util.Objects;
* @hide Only for use within the system server.
*/
public abstract class DisplayManagerInternal {
+
+ @IntDef(prefix = {"REFRESH_RATE_LIMIT_"}, value = {
+ REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RefreshRateLimitType {}
+
+ /** Refresh rate should be limited when High Brightness Mode is active. */
+ public static final int REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE = 1;
+
/**
* Called by the power manager to initialize power management facilities.
*/
@@ -296,9 +310,10 @@ public abstract class DisplayManagerInternal {
public abstract int getRefreshRateSwitchingType();
/**
+ * TODO: b/191384041 - Replace this with getRefreshRateLimitations()
* Return the refresh rate restriction for the specified display and sensor pairing. If the
* specified sensor is identified as an associated sensor in the specified display's
- * display-device-config file, then return any refresh rate restrictions that it might specify.
+ * display-device-config file, then return any refresh rate restrictions that it might define.
* If no restriction is specified, or the sensor is not associated with the display, then null
* will be returned.
*
@@ -313,6 +328,15 @@ public abstract class DisplayManagerInternal {
int displayId, String name, String type);
/**
+ * Returns a list of various refresh rate limitations for the specified display.
+ *
+ * @param displayId The display to get limitations for.
+ *
+ * @return a list of {@link RefreshRateLimitation}s describing the various limits.
+ */
+ public abstract List<RefreshRateLimitation> getRefreshRateLimitations(int displayId);
+
+ /**
* Describes the requested power state of the display.
*
* This object is intended to describe the general characteristics of the
@@ -613,4 +637,25 @@ public abstract class DisplayManagerInternal {
return "(" + min + " " + max + ")";
}
}
+
+ /**
+ * Describes a limitation on a display's refresh rate. Includes the allowed refresh rate
+ * range as well as information about when it applies, such as high-brightness-mode.
+ */
+ public static final class RefreshRateLimitation {
+ @RefreshRateLimitType public int type;
+
+ /** The range the that refresh rate should be limited to. */
+ public RefreshRateRange range;
+
+ public RefreshRateLimitation(@RefreshRateLimitType int type, float min, float max) {
+ this.type = type;
+ range = new RefreshRateRange(min, max);
+ }
+
+ @Override
+ public String toString() {
+ return "RefreshRateLimitation(" + type + ": " + range + ")";
+ }
+ }
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 688f9f1174dd..0819835f5fb5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1417,6 +1417,9 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
case FINGERPRINT_ACQUIRED_TOO_FAST:
return context.getString(
com.android.internal.R.string.fingerprint_acquired_too_fast);
+ case FINGERPRINT_ACQUIRED_IMMOBILE:
+ return context.getString(
+ com.android.internal.R.string.fingerprint_acquired_immobile);
case FINGERPRINT_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
com.android.internal.R.array.fingerprint_acquired_vendor);
diff --git a/core/java/android/hardware/input/InputDeviceVibrator.java b/core/java/android/hardware/input/InputDeviceVibrator.java
index d8150e483fd6..653c622386d6 100644
--- a/core/java/android/hardware/input/InputDeviceVibrator.java
+++ b/core/java/android/hardware/input/InputDeviceVibrator.java
@@ -56,10 +56,10 @@ final class InputDeviceVibrator extends Vibrator {
mDeviceId = deviceId;
mVibratorInfo = new VibratorInfo.Builder(vibratorId)
.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
- // Set predefined support to empty as we know input devices do not support them.
- .setSupportedEffects()
- .setSupportedPrimitives()
- .setSupportedBraking()
+ // The supported effect and braking lists are known to be empty for input devices,
+ // which is different from not being set (that means the device support is unknown).
+ .setSupportedEffects(new int[0])
+ .setSupportedBraking(new int[0])
.build();
mToken = new Binder();
}
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 662ebb356f4c..5c2855307509 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -389,6 +389,10 @@ public class VpnManager {
/**
* Starts a legacy VPN.
+ *
+ * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the
+ * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be
+ * thrown.
* @hide
*/
public void startLegacyVpn(VpnProfile profile) {
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 86cd23d1e942..752ef3e39ab6 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -352,6 +352,7 @@ public final class VcnGatewayConnectionConfig {
public int hashCode() {
return Objects.hash(
mGatewayConnectionName,
+ mTunnelConnectionParams,
mExposedCapabilities,
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu);
@@ -365,6 +366,7 @@ public final class VcnGatewayConnectionConfig {
final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
+ && mTunnelConnectionParams.equals(rhs.mTunnelConnectionParams)
&& mExposedCapabilities.equals(rhs.mExposedCapabilities)
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu;
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index fd8948cbeea8..0c3debb1b54e 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -26,6 +26,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Objects;
@@ -254,11 +255,14 @@ public class SystemVibrator extends Vibrator {
* <p>This uses the first vibrator on the list as the default one for all hardware spec, but
* uses an intersection of all vibrators to decide the capabilities and effect/primitive
* support.
+ *
+ * @hide
*/
- private static class AllVibratorsInfo extends VibratorInfo {
+ @VisibleForTesting
+ public static class AllVibratorsInfo extends VibratorInfo {
private final VibratorInfo[] mVibratorInfos;
- AllVibratorsInfo(VibratorInfo[] vibrators) {
+ public AllVibratorsInfo(VibratorInfo[] vibrators) {
super(/* id= */ -1, capabilitiesIntersection(vibrators),
vibrators.length > 0 ? vibrators[0] : VibratorInfo.EMPTY_VIBRATOR_INFO);
mVibratorInfos = vibrators;
@@ -266,6 +270,9 @@ public class SystemVibrator extends Vibrator {
@Override
public int isEffectSupported(int effectId) {
+ if (mVibratorInfos.length == 0) {
+ return Vibrator.VIBRATION_EFFECT_SUPPORT_NO;
+ }
int supported = Vibrator.VIBRATION_EFFECT_SUPPORT_YES;
for (VibratorInfo info : mVibratorInfos) {
int effectSupported = info.isEffectSupported(effectId);
@@ -280,6 +287,9 @@ public class SystemVibrator extends Vibrator {
@Override
public boolean isPrimitiveSupported(int primitiveId) {
+ if (mVibratorInfos.length == 0) {
+ return false;
+ }
for (VibratorInfo info : mVibratorInfos) {
if (!info.isPrimitiveSupported(primitiveId)) {
return false;
@@ -288,6 +298,19 @@ public class SystemVibrator extends Vibrator {
return true;
}
+ @Override
+ public int getPrimitiveDuration(int primitiveId) {
+ int maxDuration = 0;
+ for (VibratorInfo info : mVibratorInfos) {
+ int duration = info.getPrimitiveDuration(primitiveId);
+ if (duration == 0) {
+ return 0;
+ }
+ maxDuration = Math.max(maxDuration, duration);
+ }
+ return maxDuration;
+ }
+
private static int capabilitiesIntersection(VibratorInfo[] infos) {
if (infos.length == 0) {
return 0;
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 12538e6cd46b..d7893e4bbefd 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -126,6 +126,7 @@ public abstract class Vibrator {
// The default vibration intensity level for ringtones.
@VibrationIntensity
private int mDefaultRingVibrationIntensity;
+ private float mHapticChannelMaxVibrationAmplitude;
/**
* @hide to prevent subclassing from outside of the framework
@@ -134,7 +135,7 @@ public abstract class Vibrator {
public Vibrator() {
mPackageName = ActivityThread.currentPackageName();
final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
- loadVibrationIntensities(ctx);
+ loadVibrationConfig(ctx);
}
/**
@@ -142,22 +143,28 @@ public abstract class Vibrator {
*/
protected Vibrator(Context context) {
mPackageName = context.getOpPackageName();
- loadVibrationIntensities(context);
+ loadVibrationConfig(context);
}
- private void loadVibrationIntensities(Context context) {
+ private void loadVibrationConfig(Context context) {
mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
mDefaultRingVibrationIntensity = loadDefaultIntensity(context,
com.android.internal.R.integer.config_defaultRingVibrationIntensity);
+ mHapticChannelMaxVibrationAmplitude = loadFloat(context,
+ com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0);
}
private int loadDefaultIntensity(Context ctx, int resId) {
return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM;
}
+ private float loadFloat(Context ctx, int resId, float defaultValue) {
+ return ctx != null ? ctx.getResources().getFloat(resId) : defaultValue;
+ }
+
/** @hide */
protected VibratorInfo getInfo() {
return VibratorInfo.EMPTY_VIBRATOR_INFO;
@@ -297,6 +304,24 @@ public abstract class Vibrator {
}
/**
+ * Return the maximum amplitude the vibrator can play using the audio haptic channels.
+ *
+ * <p>This is a positive value, or {@link Float#NaN NaN} if it's unknown. If this returns a
+ * positive value <code>maxAmplitude</code>, then the signals from the haptic channels of audio
+ * tracks should be in the range <code>[-maxAmplitude, maxAmplitude]</code>.
+ *
+ * @return a positive value representing the maximum absolute value the device can play signals
+ * from audio haptic channels, or {@link Float#NaN NaN} if it's unknown.
+ * @hide
+ */
+ public float getHapticChannelMaximumAmplitude() {
+ if (mHapticChannelMaxVibrationAmplitude <= 0) {
+ return Float.NaN;
+ }
+ return mHapticChannelMaxVibrationAmplitude;
+ }
+
+ /**
* Configure an always-on haptics effect.
*
* @param alwaysOnId The board-specific always-on ID to configure.
diff --git a/core/java/android/os/VibratorInfo.java b/core/java/android/os/VibratorInfo.java
index 597df0811e20..486f9f139e0a 100644
--- a/core/java/android/os/VibratorInfo.java
+++ b/core/java/android/os/VibratorInfo.java
@@ -51,8 +51,11 @@ public class VibratorInfo implements Parcelable {
private final SparseBooleanArray mSupportedEffects;
@Nullable
private final SparseBooleanArray mSupportedBraking;
- @Nullable
private final SparseIntArray mSupportedPrimitives;
+ private final int mPrimitiveDelayMax;
+ private final int mCompositionSizeMax;
+ private final int mPwlePrimitiveDurationMax;
+ private final int mPwleSizeMax;
private final float mQFactor;
private final FrequencyMapping mFrequencyMapping;
@@ -62,6 +65,10 @@ public class VibratorInfo implements Parcelable {
mSupportedEffects = in.readSparseBooleanArray();
mSupportedBraking = in.readSparseBooleanArray();
mSupportedPrimitives = in.readSparseIntArray();
+ mPrimitiveDelayMax = in.readInt();
+ mCompositionSizeMax = in.readInt();
+ mPwlePrimitiveDurationMax = in.readInt();
+ mPwleSizeMax = in.readInt();
mQFactor = in.readFloat();
mFrequencyMapping = in.readParcelable(VibratorInfo.class.getClassLoader());
}
@@ -69,48 +76,50 @@ public class VibratorInfo implements Parcelable {
/**
* Default constructor.
*
- * @param id The vibrator id.
- * @param capabilities All capability flags of the vibrator, defined in IVibrator.CAP_*.
- * @param supportedEffects All supported predefined effects, enum values from {@link
- * android.hardware.vibrator.Effect}.
- * @param supportedBraking All supported braking types, enum values from {@link Braking}.
- * @param supportedPrimitives All supported primitive effects, enum values from {@link
- * android.hardware.vibrator.CompositePrimitive}.
- * @param primitiveDurations A mapping of primitive durations, where indexes are enum values
- * from {@link android.hardware.vibrator.CompositePrimitive} and the
- * values are estimated durations in milliseconds.
- * @param qFactor The vibrator quality factor.
- * @param frequencyMapping The description of the vibrator supported frequencies and max
- * amplitude mappings.
+ * @param id The vibrator id.
+ * @param capabilities All capability flags of the vibrator, defined in
+ * IVibrator.CAP_*.
+ * @param supportedEffects All supported predefined effects, enum values from
+ * {@link android.hardware.vibrator.Effect}.
+ * @param supportedBraking All supported braking types, enum values from {@link
+ * Braking}.
+ * @param supportedPrimitives All supported primitive effects, key are enum values from
+ * {@link android.hardware.vibrator.CompositePrimitive} and
+ * values are estimated durations in milliseconds.
+ * @param primitiveDelayMax The maximum delay that can be set to a composition primitive
+ * in milliseconds.
+ * @param compositionSizeMax The maximum number of primitives supported by a composition.
+ * @param pwlePrimitiveDurationMax The maximum duration of a PWLE primitive in milliseconds.
+ * @param pwleSizeMax The maximum number of primitives supported by a PWLE
+ * composition.
+ * @param qFactor The vibrator quality factor.
+ * @param frequencyMapping The description of the vibrator supported frequencies and max
+ * amplitude mappings.
* @hide
*/
- public VibratorInfo(int id, long capabilities, int[] supportedEffects, int[] supportedBraking,
- int[] supportedPrimitives, int[] primitiveDurations, float qFactor,
- @NonNull FrequencyMapping frequencyMapping) {
+ public VibratorInfo(int id, long capabilities, @Nullable SparseBooleanArray supportedEffects,
+ @Nullable SparseBooleanArray supportedBraking,
+ @NonNull SparseIntArray supportedPrimitives, int primitiveDelayMax,
+ int compositionSizeMax, int pwlePrimitiveDurationMax, int pwleSizeMax,
+ float qFactor, @NonNull FrequencyMapping frequencyMapping) {
mId = id;
mCapabilities = capabilities;
- mSupportedEffects = toSparseBooleanArray(supportedEffects);
- mSupportedBraking = toSparseBooleanArray(supportedBraking);
- mSupportedPrimitives = toSparseIntArray(supportedPrimitives, primitiveDurations);
+ mSupportedEffects = supportedEffects == null ? null : supportedEffects.clone();
+ mSupportedBraking = supportedBraking == null ? null : supportedBraking.clone();
+ mSupportedPrimitives = supportedPrimitives.clone();
+ mPrimitiveDelayMax = primitiveDelayMax;
+ mCompositionSizeMax = compositionSizeMax;
+ mPwlePrimitiveDurationMax = pwlePrimitiveDurationMax;
+ mPwleSizeMax = pwleSizeMax;
mQFactor = qFactor;
mFrequencyMapping = frequencyMapping;
}
protected VibratorInfo(int id, int capabilities, VibratorInfo baseVibrator) {
- mId = id;
- mCapabilities = capabilities;
- mSupportedEffects = baseVibrator.mSupportedEffects == null ? null :
- baseVibrator.mSupportedEffects.clone();
- mSupportedBraking = baseVibrator.mSupportedBraking == null ? null :
- baseVibrator.mSupportedBraking.clone();
- mSupportedPrimitives = baseVibrator.mSupportedPrimitives == null ? null :
- baseVibrator.mSupportedPrimitives.clone();
- mQFactor = baseVibrator.mQFactor;
- mFrequencyMapping = new FrequencyMapping(baseVibrator.mFrequencyMapping.mMinFrequencyHz,
- baseVibrator.mFrequencyMapping.mResonantFrequencyHz,
- baseVibrator.mFrequencyMapping.mFrequencyResolutionHz,
- baseVibrator.mFrequencyMapping.mSuggestedSafeRangeHz,
- baseVibrator.mFrequencyMapping.mMaxAmplitudes);
+ this(id, capabilities, baseVibrator.mSupportedEffects, baseVibrator.mSupportedBraking,
+ baseVibrator.mSupportedPrimitives, baseVibrator.mPrimitiveDelayMax,
+ baseVibrator.mCompositionSizeMax, baseVibrator.mPwlePrimitiveDurationMax,
+ baseVibrator.mPwleSizeMax, baseVibrator.mQFactor, baseVibrator.mFrequencyMapping);
}
@Override
@@ -120,6 +129,10 @@ public class VibratorInfo implements Parcelable {
dest.writeSparseBooleanArray(mSupportedEffects);
dest.writeSparseBooleanArray(mSupportedBraking);
dest.writeSparseIntArray(mSupportedPrimitives);
+ dest.writeInt(mPrimitiveDelayMax);
+ dest.writeInt(mCompositionSizeMax);
+ dest.writeInt(mPwlePrimitiveDurationMax);
+ dest.writeInt(mPwleSizeMax);
dest.writeFloat(mQFactor);
dest.writeParcelable(mFrequencyMapping, flags);
}
@@ -138,24 +151,23 @@ public class VibratorInfo implements Parcelable {
return false;
}
VibratorInfo that = (VibratorInfo) o;
- if (mSupportedPrimitives == null || that.mSupportedPrimitives == null) {
- if (mSupportedPrimitives != that.mSupportedPrimitives) {
+ int supportedPrimitivesCount = mSupportedPrimitives.size();
+ if (supportedPrimitivesCount != that.mSupportedPrimitives.size()) {
+ return false;
+ }
+ for (int i = 0; i < supportedPrimitivesCount; i++) {
+ if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) {
return false;
}
- } else {
- if (mSupportedPrimitives.size() != that.mSupportedPrimitives.size()) {
+ if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) {
return false;
}
- for (int i = 0; i < mSupportedPrimitives.size(); i++) {
- if (mSupportedPrimitives.keyAt(i) != that.mSupportedPrimitives.keyAt(i)) {
- return false;
- }
- if (mSupportedPrimitives.valueAt(i) != that.mSupportedPrimitives.valueAt(i)) {
- return false;
- }
- }
}
return mId == that.mId && mCapabilities == that.mCapabilities
+ && mPrimitiveDelayMax == that.mPrimitiveDelayMax
+ && mCompositionSizeMax == that.mCompositionSizeMax
+ && mPwlePrimitiveDurationMax == that.mPwlePrimitiveDurationMax
+ && mPwleSizeMax == that.mPwleSizeMax
&& Objects.equals(mSupportedEffects, that.mSupportedEffects)
&& Objects.equals(mSupportedBraking, that.mSupportedBraking)
&& Objects.equals(mQFactor, that.mQFactor)
@@ -166,11 +178,9 @@ public class VibratorInfo implements Parcelable {
public int hashCode() {
int hashCode = Objects.hash(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
mQFactor, mFrequencyMapping);
- if (mSupportedPrimitives != null) {
- for (int i = 0; i < mSupportedPrimitives.size(); i++) {
- hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i);
- hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i);
- }
+ for (int i = 0; i < mSupportedPrimitives.size(); i++) {
+ hashCode = 31 * hashCode + mSupportedPrimitives.keyAt(i);
+ hashCode = 31 * hashCode + mSupportedPrimitives.valueAt(i);
}
return hashCode;
}
@@ -184,6 +194,10 @@ public class VibratorInfo implements Parcelable {
+ ", mSupportedEffects=" + Arrays.toString(getSupportedEffectsNames())
+ ", mSupportedBraking=" + Arrays.toString(getSupportedBrakingNames())
+ ", mSupportedPrimitives=" + Arrays.toString(getSupportedPrimitivesNames())
+ + ", mPrimitiveDelayMax=" + mPrimitiveDelayMax
+ + ", mCompositionSizeMax=" + mCompositionSizeMax
+ + ", mPwlePrimitiveDurationMax=" + mPwlePrimitiveDurationMax
+ + ", mPwleSizeMax=" + mPwleSizeMax
+ ", mQFactor=" + mQFactor
+ ", mFrequencyMapping=" + mFrequencyMapping
+ '}';
@@ -247,7 +261,7 @@ public class VibratorInfo implements Parcelable {
*/
public boolean isPrimitiveSupported(
@VibrationEffect.Composition.PrimitiveType int primitiveId) {
- return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS) && mSupportedPrimitives != null
+ return hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)
&& (mSupportedPrimitives.indexOfKey(primitiveId) >= 0);
}
@@ -260,7 +274,43 @@ public class VibratorInfo implements Parcelable {
*/
public int getPrimitiveDuration(
@VibrationEffect.Composition.PrimitiveType int primitiveId) {
- return mSupportedPrimitives != null ? mSupportedPrimitives.get(primitiveId) : 0;
+ return mSupportedPrimitives.get(primitiveId);
+ }
+
+ /**
+ * Query the maximum delay supported for a primitive in a composed effect.
+ *
+ * @return The max delay in milliseconds, or zero if unlimited.
+ */
+ public int getPrimitiveDelayMax() {
+ return mPrimitiveDelayMax;
+ }
+
+ /**
+ * Query the maximum number of primitives supported in a composed effect.
+ *
+ * @return The max number of primitives supported, or zero if unlimited.
+ */
+ public int getCompositionSizeMax() {
+ return mCompositionSizeMax;
+ }
+
+ /**
+ * Query the maximum duration supported for a primitive in a PWLE composition.
+ *
+ * @return The max duration in milliseconds, or zero if unlimited.
+ */
+ public int getPwlePrimitiveDurationMax() {
+ return mPwlePrimitiveDurationMax;
+ }
+
+ /**
+ * Query the maximum number of primitives supported in a PWLE composition.
+ *
+ * @return The max number of primitives supported, or zero if unlimited.
+ */
+ public int getPwleSizeMax() {
+ return mPwleSizeMax;
}
/**
@@ -408,52 +458,15 @@ public class VibratorInfo implements Parcelable {
}
private String[] getSupportedPrimitivesNames() {
- if (mSupportedPrimitives == null) {
- return new String[0];
- }
- String[] names = new String[mSupportedPrimitives.size()];
- for (int i = 0; i < mSupportedPrimitives.size(); i++) {
+ int supportedPrimitivesCount = mSupportedPrimitives.size();
+ String[] names = new String[supportedPrimitivesCount];
+ for (int i = 0; i < supportedPrimitivesCount; i++) {
names[i] = VibrationEffect.Composition.primitiveToString(mSupportedPrimitives.keyAt(i));
}
return names;
}
/**
- * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is mapped
- * to {@code true}.
- */
- @Nullable
- private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) {
- if (supportedKeys == null) {
- return null;
- }
- SparseBooleanArray array = new SparseBooleanArray();
- for (int key : supportedKeys) {
- array.put(key, true);
- }
- return array;
- }
-
- /**
- * Create a {@link SparseIntArray} from given {@code supportedKeys} where each key is mapped
- * to the value indexed by it.
- *
- * <p>If {@code values} is null or does not contain a given key as a index, then zero is stored
- * to the sparse array so it can still be used to query the supported keys.
- */
- @Nullable
- private static SparseIntArray toSparseIntArray(int[] supportedKeys, int[] values) {
- if (supportedKeys == null) {
- return null;
- }
- SparseIntArray array = new SparseIntArray();
- for (int key : supportedKeys) {
- array.put(key, (values == null || key >= values.length) ? 0 : values[key]);
- }
- return array;
- }
-
- /**
* Describes how frequency should be mapped to absolute values for a specific {@link Vibrator}.
*
* <p>This mapping is defined by the following parameters:
@@ -675,11 +688,14 @@ public class VibratorInfo implements Parcelable {
/** @hide */
public static final class Builder {
private final int mId;
- private int mCapabilities = 0;
- private int[] mSupportedEffects = null;
- private int[] mSupportedBraking = null;
- private int[] mSupportedPrimitives = null;
- private int[] mPrimitiveDurations = new int[0];
+ private long mCapabilities;
+ private SparseBooleanArray mSupportedEffects;
+ private SparseBooleanArray mSupportedBraking;
+ private SparseIntArray mSupportedPrimitives = new SparseIntArray();
+ private int mPrimitiveDelayMax;
+ private int mCompositionSizeMax;
+ private int mPwlePrimitiveDurationMax;
+ private int mPwleSizeMax;
private float mQFactor = Float.NaN;
private FrequencyMapping mFrequencyMapping =
new FrequencyMapping(Float.NaN, Float.NaN, Float.NaN, Float.NaN, null);
@@ -691,7 +707,7 @@ public class VibratorInfo implements Parcelable {
/** Configure the vibrator capabilities with a combination of IVibrator.CAP_* values. */
@NonNull
- public Builder setCapabilities(int capabilities) {
+ public Builder setCapabilities(long capabilities) {
mCapabilities = capabilities;
return this;
}
@@ -699,34 +715,49 @@ public class VibratorInfo implements Parcelable {
/** Configure the effects supported with {@link android.hardware.vibrator.Effect} values. */
@NonNull
public Builder setSupportedEffects(int... supportedEffects) {
- mSupportedEffects = supportedEffects;
+ mSupportedEffects = toSparseBooleanArray(supportedEffects);
return this;
}
/** Configure braking supported with {@link android.hardware.vibrator.Braking} values. */
@NonNull
public Builder setSupportedBraking(int... supportedBraking) {
- mSupportedBraking = supportedBraking;
+ mSupportedBraking = toSparseBooleanArray(supportedBraking);
return this;
}
- /**
- * Configure the primitives supported with
- * {@link android.hardware.vibrator.CompositePrimitive} values.
- */
+ /** Configure maximum duration, in milliseconds, of a PWLE primitive. */
+ @NonNull
+ public Builder setPwlePrimitiveDurationMax(int pwlePrimitiveDurationMax) {
+ mPwlePrimitiveDurationMax = pwlePrimitiveDurationMax;
+ return this;
+ }
+
+ /** Configure maximum number of primitives supported in a single PWLE composed effect. */
@NonNull
- public Builder setSupportedPrimitives(int... supportedPrimitives) {
- mSupportedPrimitives = supportedPrimitives;
+ public Builder setPwleSizeMax(int pwleSizeMax) {
+ mPwleSizeMax = pwleSizeMax;
return this;
}
/** Configure the duration of a {@link android.hardware.vibrator.CompositePrimitive}. */
@NonNull
- public Builder setPrimitiveDuration(int primitiveId, int duration) {
- if (mPrimitiveDurations.length <= primitiveId) {
- mPrimitiveDurations = Arrays.copyOf(mPrimitiveDurations, primitiveId + 1);
- }
- mPrimitiveDurations[primitiveId] = duration;
+ public Builder setSupportedPrimitive(int primitiveId, int duration) {
+ mSupportedPrimitives.put(primitiveId, duration);
+ return this;
+ }
+
+ /** Configure maximum delay, in milliseconds, supported in a composed effect primitive. */
+ @NonNull
+ public Builder setPrimitiveDelayMax(int primitiveDelayMax) {
+ mPrimitiveDelayMax = primitiveDelayMax;
+ return this;
+ }
+
+ /** Configure maximum number of primitives supported in a single composed effect. */
+ @NonNull
+ public Builder setCompositionSizeMax(int compositionSizeMax) {
+ mCompositionSizeMax = compositionSizeMax;
return this;
}
@@ -748,7 +779,25 @@ public class VibratorInfo implements Parcelable {
@NonNull
public VibratorInfo build() {
return new VibratorInfo(mId, mCapabilities, mSupportedEffects, mSupportedBraking,
- mSupportedPrimitives, mPrimitiveDurations, mQFactor, mFrequencyMapping);
+ mSupportedPrimitives, mPrimitiveDelayMax, mCompositionSizeMax,
+ mPwlePrimitiveDurationMax, mPwleSizeMax, mQFactor, mFrequencyMapping);
+ }
+
+ /**
+ * Create a {@link SparseBooleanArray} from given {@code supportedKeys} where each key is
+ * mapped
+ * to {@code true}.
+ */
+ @Nullable
+ private static SparseBooleanArray toSparseBooleanArray(int[] supportedKeys) {
+ if (supportedKeys == null) {
+ return null;
+ }
+ SparseBooleanArray array = new SparseBooleanArray();
+ for (int key : supportedKeys) {
+ array.put(key, true);
+ }
+ return array;
}
}
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index c5d0cd40bc6d..4ef0e6e785e8 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -908,9 +908,32 @@ public final class PermissionManager {
*/
public static boolean shouldShowPackageForIndicatorCached(@NonNull Context context,
@NonNull String packageName) {
- if (SYSTEM_PKG.equals(packageName)) {
- return false;
+ return !getIndicatorExemptedPackages(context).contains(packageName);
+ }
+
+ /**
+ * Get the list of packages that are not shown by the indicators. Only a select few roles, and
+ * the system app itself, are hidden. These values are updated at most every 15 seconds.
+ * @hide
+ */
+ public static Set<String> getIndicatorExemptedPackages(@NonNull Context context) {
+ updateIndicatorExemptedPackages(context);
+ ArraySet<String> pkgNames = new ArraySet<>();
+ pkgNames.add(SYSTEM_PKG);
+ for (int i = 0; i < INDICATOR_EXEMPTED_PACKAGES.length; i++) {
+ String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
+ if (exemptedPackage != null) {
+ pkgNames.add(exemptedPackage);
+ }
}
+ return pkgNames;
+ }
+
+ /**
+ * Update the cached indicator exempted packages
+ * @hide
+ */
+ public static void updateIndicatorExemptedPackages(@NonNull Context context) {
long now = SystemClock.elapsedRealtime();
if (sLastIndicatorUpdateTime == -1
|| (now - sLastIndicatorUpdateTime) > EXEMPTED_INDICATOR_ROLE_UPDATE_FREQUENCY_MS) {
@@ -919,14 +942,6 @@ public final class PermissionManager {
INDICATOR_EXEMPTED_PACKAGES[i] = context.getString(EXEMPTED_ROLES[i]);
}
}
- for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
- String exemptedPackage = INDICATOR_EXEMPTED_PACKAGES[i];
- if (exemptedPackage != null && exemptedPackage.equals(packageName)) {
- return false;
- }
- }
-
- return true;
}
/**
* Gets the list of packages that have permissions that specified
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index d4e548e1df1e..791764b4342f 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -410,7 +410,9 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis
int usageAttr = usage.getPackageIdHash();
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
- if (!proxies.containsKey(usageAttr) && usage.proxy != null) {
+ // TODO remove once camera converted
+ if (!proxies.containsKey(usageAttr) && usage.proxy != null
+ && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
proxyLabels.put(usage, new ArrayList<>());
proxyPackages.add(usage.getPackageIdHash());
}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 0b11aeb1ed65..3b4f7e241852 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -124,7 +124,6 @@ public final class KeymasterDefs {
public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION =
Tag.DEVICE_UNIQUE_ATTESTATION; // KM_BOOL | 720;
- public static final int KM_TAG_ASSOCIATED_DATA = Tag.ASSOCIATED_DATA; // KM_BYTES | 1000;
public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
public static final int KM_TAG_RESET_SINCE_ID_ROTATION =
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index 1188a3f1021e..74a735518120 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -55,12 +55,25 @@ public final class ActivityEvent implements Parcelable {
*/
public static final int TYPE_ACTIVITY_DESTROYED = Event.ACTIVITY_DESTROYED;
+ /**
+ * TODO: change to public field.
+ * The activity was started.
+ *
+ * <p>There are some reason, ACTIVITY_START cannot be added into UsageStats. We don't depend on
+ * UsageEvents for Activity start.
+ * </p>
+ *
+ * @hide
+ */
+ public static final int TYPE_ACTIVITY_STARTED = 10000;
+
/** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_ACTIVITY_RESUMED,
TYPE_ACTIVITY_PAUSED,
TYPE_ACTIVITY_STOPPED,
- TYPE_ACTIVITY_DESTROYED
+ TYPE_ACTIVITY_DESTROYED,
+ TYPE_ACTIVITY_STARTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface ActivityEventType{}
@@ -86,7 +99,8 @@ public final class ActivityEvent implements Parcelable {
* Gets the event type.
*
* @return either {@link #TYPE_ACTIVITY_RESUMED}, {@value #TYPE_ACTIVITY_PAUSED},
- * {@value #TYPE_ACTIVITY_STOPPED}, or {@value #TYPE_ACTIVITY_DESTROYED}.
+ * {@value #TYPE_ACTIVITY_STOPPED}, {@value #TYPE_ACTIVITY_DESTROYED} or 10000 if the Activity
+ * was started.
*/
@ActivityEventType
public int getEventType() {
@@ -104,6 +118,8 @@ public final class ActivityEvent implements Parcelable {
return "ACTIVITY_STOPPED";
case TYPE_ACTIVITY_DESTROYED:
return "ACTIVITY_DESTROYED";
+ case TYPE_ACTIVITY_STARTED:
+ return "ACTIVITY_STARTED";
default:
return "UKNOWN_TYPE: " + type;
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 67b97cee1b51..41374167cc56 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -263,6 +263,7 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
private static final int MSG_DETECTION_RESUME = 5;
private static final int MSG_HOTWORD_REJECTED = 6;
private static final int MSG_HOTWORD_STATUS_REPORTED = 7;
+ private static final int MSG_PROCESS_RESTARTED = 8;
private final String mText;
private final Locale mLocale;
@@ -1212,6 +1213,12 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
message.arg1 = status;
message.sendToTarget();
}
+
+ @Override
+ public void onProcessRestarted() {
+ Slog.i(TAG, "onProcessRestarted");
+ mHandler.sendEmptyMessage(MSG_PROCESS_RESTARTED);
+ }
}
class MyHandler extends Handler {
@@ -1246,6 +1253,9 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector {
case MSG_HOTWORD_STATUS_REPORTED:
mExternalCallback.onHotwordDetectionServiceInitialized(msg.arg1);
break;
+ case MSG_PROCESS_RESTARTED:
+ mExternalCallback.onHotwordDetectionServiceRestarted();
+ break;
default:
super.handleMessage(msg);
}
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index 846f2f94d055..315392bf6a58 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -20,11 +20,18 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.res.Resources;
+import android.media.AudioRecord;
import android.media.MediaSyncEvent;
+import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import com.android.internal.R;
import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
/**
* Represents a result supporting the hotword detection.
@@ -187,16 +194,20 @@ public final class HotwordDetectedResult implements Parcelable {
return new PersistableBundle();
}
+ private static int sMaxBundleSize = -1;
+
/**
* Returns the maximum byte size of the information contained in the bundle.
*
- * <p>The total size will be calculated as a sum of byte sizes over all bundle keys.
- *
- * <p>For example, for a bundle containing a single key: {@code "example_key" -> 42.0f}, the
- * bundle size will be {@code 11 + Float.BYTES = 15} bytes.
+ * <p>The total size will be calculated by how much bundle data should be written into the
+ * Parcel.
*/
public static int getMaxBundleSize() {
- return 50;
+ if (sMaxBundleSize < 0) {
+ sMaxBundleSize = Resources.getSystem().getInteger(
+ R.integer.config_hotwordDetectedResultMaxBundleSize);
+ }
+ return sMaxBundleSize;
}
/**
@@ -212,6 +223,34 @@ public final class HotwordDetectedResult implements Parcelable {
return mMediaSyncEvent;
}
+ /**
+ * Returns how many bytes should be written into the Parcel
+ *
+ * @hide
+ */
+ public static int getParcelableSize(@NonNull Parcelable parcelable) {
+ final Parcel p = Parcel.obtain();
+ parcelable.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ final int size = p.dataSize();
+ p.recycle();
+ return size;
+ }
+
+ private void onConstructed() {
+ Preconditions.checkArgumentInRange(mScore, 0, getMaxScore(), "score");
+ Preconditions.checkArgumentInRange(mPersonalizedScore, 0, getMaxScore(),
+ "personalizedScore");
+ Preconditions.checkArgumentInRange(mHotwordPhraseId, 0, getMaxHotwordPhraseId(),
+ "hotwordPhraseId");
+ Preconditions.checkArgumentInRange((long) mHotwordDurationMillis, 0,
+ AudioRecord.getMaxSharedAudioHistoryMillis(), "hotwordDurationMillis");
+ if (!mExtras.isEmpty()) {
+ Preconditions.checkArgumentInRange(getParcelableSize(mExtras), 0, getMaxBundleSize(),
+ "extras");
+ }
+ }
+
// Code below generated by codegen v1.0.23.
@@ -290,7 +329,7 @@ public final class HotwordDetectedResult implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mExtras);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
/**
@@ -422,7 +461,7 @@ public final class HotwordDetectedResult implements Parcelable {
//noinspection PointlessBooleanExpression
return true
&& mConfidenceLevel == that.mConfidenceLevel
- && java.util.Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
+ && Objects.equals(mMediaSyncEvent, that.mMediaSyncEvent)
&& mHotwordOffsetMillis == that.mHotwordOffsetMillis
&& mHotwordDurationMillis == that.mHotwordDurationMillis
&& mAudioChannel == that.mAudioChannel
@@ -430,7 +469,7 @@ public final class HotwordDetectedResult implements Parcelable {
&& mScore == that.mScore
&& mPersonalizedScore == that.mPersonalizedScore
&& mHotwordPhraseId == that.mHotwordPhraseId
- && java.util.Objects.equals(mExtras, that.mExtras);
+ && Objects.equals(mExtras, that.mExtras);
}
@Override
@@ -441,7 +480,7 @@ public final class HotwordDetectedResult implements Parcelable {
int _hash = 1;
_hash = 31 * _hash + mConfidenceLevel;
- _hash = 31 * _hash + java.util.Objects.hashCode(mMediaSyncEvent);
+ _hash = 31 * _hash + Objects.hashCode(mMediaSyncEvent);
_hash = 31 * _hash + mHotwordOffsetMillis;
_hash = 31 * _hash + mHotwordDurationMillis;
_hash = 31 * _hash + mAudioChannel;
@@ -449,13 +488,13 @@ public final class HotwordDetectedResult implements Parcelable {
_hash = 31 * _hash + mScore;
_hash = 31 * _hash + mPersonalizedScore;
_hash = 31 * _hash + mHotwordPhraseId;
- _hash = 31 * _hash + java.util.Objects.hashCode(mExtras);
+ _hash = 31 * _hash + Objects.hashCode(mExtras);
return _hash;
}
@Override
@DataClass.Generated.Member
- public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
@@ -481,7 +520,7 @@ public final class HotwordDetectedResult implements Parcelable {
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ HotwordDetectedResult(@NonNull android.os.Parcel in) {
+ /* package-private */ HotwordDetectedResult(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -512,7 +551,7 @@ public final class HotwordDetectedResult implements Parcelable {
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mExtras);
- // onConstructed(); // You can define this method to get a callback
+ onConstructed();
}
@DataClass.Generated.Member
@@ -524,7 +563,7 @@ public final class HotwordDetectedResult implements Parcelable {
}
@Override
- public HotwordDetectedResult createFromParcel(@NonNull android.os.Parcel in) {
+ public HotwordDetectedResult createFromParcel(@NonNull Parcel in) {
return new HotwordDetectedResult(in);
}
};
@@ -745,10 +784,10 @@ public final class HotwordDetectedResult implements Parcelable {
}
@DataClass.Generated(
- time = 1621943150502L,
+ time = 1624361647985L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
- inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+ inputSignatures = "public static final int CONFIDENCE_LEVEL_NONE\npublic static final int CONFIDENCE_LEVEL_LOW\npublic static final int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM\npublic static final int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final int CONFIDENCE_LEVEL_HIGH\npublic static final int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final int HOTWORD_OFFSET_UNSET\npublic static final int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate int mHotwordOffsetMillis\nprivate int mHotwordDurationMillis\nprivate int mAudioChannel\nprivate boolean mHotwordDetectionPersonalized\nprivate final int mScore\nprivate final int mPersonalizedScore\nprivate final int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static int sMaxBundleSize\nprivate static int defaultConfidenceLevel()\nprivate static int defaultScore()\nprivate static int defaultPersonalizedScore()\npublic static int getMaxScore()\nprivate static int defaultHotwordPhraseId()\npublic static int getMaxHotwordPhraseId()\nprivate static android.os.PersistableBundle defaultExtras()\npublic static int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\npublic static int getParcelableSize(android.os.Parcelable)\nprivate void onConstructed()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/voice/HotwordDetectionService.java b/core/java/android/service/voice/HotwordDetectionService.java
index b66d93d6316e..567ee2f65565 100644
--- a/core/java/android/service/voice/HotwordDetectionService.java
+++ b/core/java/android/service/voice/HotwordDetectionService.java
@@ -76,6 +76,7 @@ public abstract class HotwordDetectionService extends Service {
private static final boolean DBG = true;
private static final long UPDATE_TIMEOUT_MILLIS = 5000;
+
/** @hide */
public static final String KEY_INITIALIZATION_STATUS = "initialization_status";
@@ -291,9 +292,7 @@ public abstract class HotwordDetectionService extends Service {
@Nullable PersistableBundle options,
@Nullable SharedMemory sharedMemory,
@DurationMillisLong long callbackTimeoutMillis,
- @Nullable IntConsumer statusCallback) {
- // TODO: Handle the unimplemented case by throwing?
- }
+ @Nullable IntConsumer statusCallback) {}
/**
* Called when the {@link VoiceInteractionService} requests that this service
@@ -390,6 +389,14 @@ public abstract class HotwordDetectionService extends Service {
*/
public void onDetected(@NonNull HotwordDetectedResult result) {
requireNonNull(result);
+ final PersistableBundle persistableBundle = result.getExtras();
+ if (!persistableBundle.isEmpty() && HotwordDetectedResult.getParcelableSize(
+ persistableBundle) > HotwordDetectedResult.getMaxBundleSize()) {
+ throw new IllegalArgumentException(
+ "The bundle size of result is larger than max bundle size ("
+ + HotwordDetectedResult.getMaxBundleSize()
+ + ") of HotwordDetectedResult");
+ }
try {
mRemoteCallback.onDetected(result);
} catch (RemoteException e) {
diff --git a/core/java/android/service/voice/SoftwareHotwordDetector.java b/core/java/android/service/voice/SoftwareHotwordDetector.java
index 204e7df89706..fb540b1622e6 100644
--- a/core/java/android/service/voice/SoftwareHotwordDetector.java
+++ b/core/java/android/service/voice/SoftwareHotwordDetector.java
@@ -122,7 +122,7 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
this.mCallback = callback;
}
- /** TODO: onDetected */
+ /** Called when the detected result is valid. */
@Override
public void onDetected(
@Nullable HotwordDetectedResult hotwordDetectedResult,
@@ -150,33 +150,45 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
public void onKeyphraseDetected(
SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
HotwordDetectedResult result) {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onKeyphraseDetected event");
+ }
}
@Override
public void onGenericSoundTriggerDetected(
SoundTrigger.GenericRecognitionEvent recognitionEvent) throws RemoteException {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onGenericSoundTriggerDetected event");
+ }
}
@Override
public void onRejected(HotwordRejectedResult result) throws RemoteException {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onRejected event");
+ }
}
@Override
public void onError(int status) throws RemoteException {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onError (" + status + ") event");
+ }
}
@Override
public void onRecognitionPaused() throws RemoteException {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onRecognitionPaused event");
+ }
}
@Override
public void onRecognitionResumed() throws RemoteException {
-
+ if (DEBUG) {
+ Slog.i(TAG, "Ignored #onRecognitionResumed event");
+ }
}
@Override
@@ -187,6 +199,14 @@ class SoftwareHotwordDetector extends AbstractHotwordDetector {
mCallback,
status));
}
+
+ @Override
+ public void onProcessRestarted() throws RemoteException {
+ Slog.v(TAG, "onProcessRestarted()");
+ mHandler.sendMessage(obtainMessage(
+ HotwordDetector.Callback::onHotwordDetectionServiceRestarted,
+ mCallback));
+ }
}
/** @hide */
diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java
index e307b969ef91..761a2b88dec2 100644
--- a/core/java/android/view/CrossWindowBlurListeners.java
+++ b/core/java/android/view/CrossWindowBlurListeners.java
@@ -73,14 +73,14 @@ public final class CrossWindowBlurListeners {
return instance;
}
- boolean isCrossWindowBlurEnabled() {
+ public boolean isCrossWindowBlurEnabled() {
synchronized (sLock) {
attachInternalListenerIfNeededLocked();
return mCrossWindowBlurEnabled;
}
}
- void addListener(@NonNull @CallbackExecutor Executor executor,
+ public void addListener(@NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<Boolean> listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
Preconditions.checkNotNull(executor, "executor cannot be null");
@@ -94,7 +94,7 @@ public final class CrossWindowBlurListeners {
}
- void removeListener(Consumer<Boolean> listener) {
+ public void removeListener(Consumer<Boolean> listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
synchronized (sLock) {
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 8080883c2b3e..145607ada4f4 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1265,7 +1265,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
stateChanged |= getSourceConsumer(types.valueAt(j)).notifyAnimationFinished();
}
- if (invokeCallback && runningAnimation.startDispatched) {
+ if (invokeCallback) {
dispatchAnimationEnd(runningAnimation.runner.getAnimation());
}
break;
diff --git a/core/java/android/view/ScrollCaptureTarget.java b/core/java/android/view/ScrollCaptureTarget.java
index 44017ed0d831..a8bb037af5f9 100644
--- a/core/java/android/view/ScrollCaptureTarget.java
+++ b/core/java/android/view/ScrollCaptureTarget.java
@@ -21,13 +21,10 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiThread;
-import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.CancellationSignal;
-import com.android.internal.util.FastMath;
-
import java.io.PrintWriter;
import java.util.function.Consumer;
@@ -43,8 +40,7 @@ public final class ScrollCaptureTarget {
private final int mHint;
private Rect mScrollBounds;
- private final float[] mTmpFloatArr = new float[2];
- private final Matrix mMatrixViewLocalToWindow = new Matrix();
+ private final int[] mTmpIntArr = new int[2];
public ScrollCaptureTarget(@NonNull View scrollTarget, @NonNull Rect localVisibleRect,
@NonNull Point positionInWindow, @NonNull ScrollCaptureCallback callback) {
@@ -117,28 +113,15 @@ public final class ScrollCaptureTarget {
}
}
- private static void zero(float[] pointArray) {
- pointArray[0] = 0;
- pointArray[1] = 0;
- }
-
- private static void roundIntoPoint(Point pointObj, float[] pointArray) {
- pointObj.x = FastMath.round(pointArray[0]);
- pointObj.y = FastMath.round(pointArray[1]);
- }
-
/**
- * Refresh the local visible bounds and it's offset within the window, based on the current
+ * Refresh the local visible bounds and its offset within the window, based on the current
* state of the {@code containing view}.
*/
@UiThread
public void updatePositionInWindow() {
- mMatrixViewLocalToWindow.reset();
- mContainingView.transformMatrixToGlobal(mMatrixViewLocalToWindow);
-
- zero(mTmpFloatArr);
- mMatrixViewLocalToWindow.mapPoints(mTmpFloatArr);
- roundIntoPoint(mPositionInWindow, mTmpFloatArr);
+ mContainingView.getLocationInWindow(mTmpIntArr);
+ mPositionInWindow.x = mTmpIntArr[0];
+ mPositionInWindow.y = mTmpIntArr[1];
}
public String toString() {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index f34cd8f9de50..4e66ceb76a60 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -233,6 +233,7 @@ public final class SurfaceControl implements Parcelable {
private static native void nativeRemoveJankDataListener(long nativeListener);
private static native long nativeCreateJankDataListenerWrapper(OnJankDataListener listener);
private static native int nativeGetGPUContextPriority();
+ private static native void nativeSetTransformHint(long nativeObject, int transformHint);
@Nullable
@GuardedBy("mLock")
@@ -348,6 +349,8 @@ public final class SurfaceControl implements Parcelable {
@GuardedBy("mLock")
private int mHeight;
+ private int mTransformHint;
+
private WeakReference<View> mLocalOwnerView;
static GlobalTransactionWrapper sGlobalTransaction;
@@ -605,6 +608,7 @@ public final class SurfaceControl implements Parcelable {
mName = other.mName;
mWidth = other.mWidth;
mHeight = other.mHeight;
+ mTransformHint = other.mTransformHint;
mLocalOwnerView = other.mLocalOwnerView;
assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);
}
@@ -1467,6 +1471,7 @@ public final class SurfaceControl implements Parcelable {
mName = in.readString8();
mWidth = in.readInt();
mHeight = in.readInt();
+ mTransformHint = in.readInt();
long object = 0;
if (in.readInt() != 0) {
@@ -1485,6 +1490,7 @@ public final class SurfaceControl implements Parcelable {
dest.writeString8(mName);
dest.writeInt(mWidth);
dest.writeInt(mHeight);
+ dest.writeInt(mTransformHint);
if (mNativeObject == 0) {
dest.writeInt(0);
} else {
@@ -3602,4 +3608,27 @@ public final class SurfaceControl implements Parcelable {
mHeight = h;
nativeUpdateDefaultBufferSize(mNativeObject, w, h);
}
+
+ /**
+ * @hide
+ */
+ public int getTransformHint() {
+ return mTransformHint;
+ }
+
+ /**
+ * Update the transform hint of current SurfaceControl. Only affect if type is
+ * {@link #FX_SURFACE_BLAST}
+ *
+ * The transform hint is used to prevent allocating a buffer of different size when a
+ * layer is rotated. The producer can choose to consume the hint and allocate the buffer
+ * with the same size.
+ * @hide
+ */
+ public void setTransformHint(@Surface.Rotation int transformHint) {
+ if (mTransformHint != transformHint) {
+ mTransformHint = transformHint;
+ nativeSetTransformHint(mNativeObject, transformHint);
+ }
+ }
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6b0bb9df5468..4f2cf6d9001e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -30,7 +30,6 @@ import android.graphics.BLASTBufferQueue;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.HardwareRenderer;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -214,6 +213,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
+ int mTransformHint = 0;
private boolean mGlobalListenersAdded;
private boolean mAttachedToWindow;
@@ -944,7 +944,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
- boolean creating, boolean sizeChanged) {
+ boolean creating, boolean sizeChanged, boolean hintChanged) {
boolean realSizeChanged = false;
mSurfaceLock.lock();
@@ -1009,7 +1009,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
}
mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
- if (sizeChanged && !creating) {
+ if ((sizeChanged || hintChanged) && !creating) {
setBufferSize(mTmpTransaction);
}
@@ -1081,17 +1081,18 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|| mWindowSpaceTop != mLocation[1];
final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
|| getHeight() != mScreenRect.height();
-
+ final boolean hintChanged = viewRoot.getSurfaceTransformHint() != mTransformHint;
if (creating || formatChanged || sizeChanged || visibleChanged ||
(mUseAlpha && alphaChanged) || windowVisibleChanged ||
- positionChanged || layoutSizeChanged) {
+ positionChanged || layoutSizeChanged || hintChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ " visible=" + visibleChanged + " alpha=" + alphaChanged
+ + " hint=" + hintChanged
+ " mUseAlpha=" + mUseAlpha
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
@@ -1105,6 +1106,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
mLastWindowVisibility = mWindowVisibility;
+ mTransformHint = viewRoot.getSurfaceTransformHint();
mScreenRect.left = mWindowSpaceLeft;
mScreenRect.top = mWindowSpaceTop;
@@ -1130,9 +1132,9 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
final boolean realSizeChanged = performSurfaceTransaction(viewRoot,
- translator, creating, sizeChanged);
- final boolean redrawNeeded = sizeChanged || creating ||
- (mVisible && !mDrawFinished);
+ translator, creating, sizeChanged, hintChanged);
+ final boolean redrawNeeded = sizeChanged || creating || hintChanged
+ || (mVisible && !mDrawFinished);
try {
SurfaceHolder.Callback[] callbacks = null;
@@ -1158,7 +1160,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
c.surfaceCreated(mSurfaceHolder);
}
}
- if (creating || formatChanged || sizeChanged
+ if (creating || formatChanged || sizeChanged || hintChanged
|| visibleChanged || realSizeChanged) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "surfaceChanged -- format=" + mFormat
@@ -1234,6 +1236,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
private void setBufferSize(Transaction transaction) {
if (mUseBlastAdapter) {
+ mBlastSurfaceControl.setTransformHint(mTransformHint);
mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight, mFormat);
} else {
transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
@@ -1330,6 +1333,8 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
}
+ mTransformHint = viewRoot.getSurfaceTransformHint();
+ mBlastSurfaceControl.setTransformHint(mTransformHint);
mBlastBufferQueue = new BLASTBufferQueue(name, mBlastSurfaceControl, mSurfaceWidth,
mSurfaceHeight, mFormat);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cf8c746d6ecb..573ae998305e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -10382,4 +10382,8 @@ public final class ViewRootImpl implements ViewParent,
});
return true;
}
+
+ int getSurfaceTransformHint() {
+ return mSurfaceControl.getTransformHint();
+ }
}
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index d8cd6056de90..27821fd6608d 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -110,6 +110,10 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host {
@Override
public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) {
if (DEBUG) Log.d(TAG, "windowInsetsAnimation ended");
+ if (mViewRoot.mView == null) {
+ // The view has already detached from window.
+ return;
+ }
mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation);
}
diff --git a/core/java/android/view/WindowInsetsAnimation.java b/core/java/android/view/WindowInsetsAnimation.java
index ab5b5ba51a6e..6576eea40496 100644
--- a/core/java/android/view/WindowInsetsAnimation.java
+++ b/core/java/android/view/WindowInsetsAnimation.java
@@ -360,6 +360,13 @@ public final class WindowInsetsAnimation {
* finished, and then revert to the starting state of the animation in the first
* {@link #onProgress} callback by using post-layout view properties like {@link View#setX}
* and related methods.
+ *
+ * <p>Note that the animation might be cancelled before {@link #onStart} is dispatched. On
+ * {@link android.os.Build.VERSION_CODES#S S} and later, {@link #onEnd} is immediately
+ * dispatched without an {@link #onStart} in that case.
+ * On {@link android.os.Build.VERSION_CODES#R R}, no callbacks are dispatched after
+ * {@code #onPrepare} for such an animation.
+ *
* <p>
* Note: If the animation is application controlled by using
* {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 10ae69118f54..ce6d034c585e 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -286,6 +286,15 @@ public final class ContentCaptureEvent implements Parcelable {
return this;
}
+ boolean hasSameComposingSpan(@NonNull ContentCaptureEvent other) {
+ return mComposingStart == other.mComposingStart && mComposingEnd == other.mComposingEnd;
+ }
+
+ boolean hasSameSelectionSpan(@NonNull ContentCaptureEvent other) {
+ return mSelectionStartIndex == other.mSelectionStartIndex
+ && mSelectionEndIndex == other.mSelectionEndIndex;
+ }
+
private int getComposingStart() {
return mComposingStart;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index bcb914208958..7ec9d34bd364 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -368,7 +368,10 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
final CharSequence lastText = lastEvent.getText();
final boolean bothNonEmpty = !TextUtils.isEmpty(lastText)
&& !TextUtils.isEmpty(text);
- boolean equalContent = TextUtils.equals(lastText, text);
+ boolean equalContent =
+ TextUtils.equals(lastText, text)
+ && lastEvent.hasSameComposingSpan(event)
+ && lastEvent.hasSameSelectionSpan(event);
if (equalContent) {
addEvent = false;
} else if (bothNonEmpty) {
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index bdd12063e6cf..c4540b0d8726 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -163,6 +163,17 @@ public class BaseInputConnection implements InputConnection {
}
/**
+ * Called after only the composing region is modified (so it isn't called if the text also
+ * changes).
+ * <p>
+ * Default implementation does nothing.
+ *
+ * @hide
+ */
+ public void endComposingRegionEditInternal() {
+ }
+
+ /**
* Default implementation calls {@link #finishComposingText()} and
* {@code setImeConsumesInput(false)}.
*/
@@ -468,6 +479,7 @@ public class BaseInputConnection implements InputConnection {
// Note: sendCurrentText does nothing unless mFallbackMode is set
sendCurrentText();
endBatchEdit();
+ endComposingRegionEditInternal();
}
return true;
}
@@ -734,6 +746,7 @@ public class BaseInputConnection implements InputConnection {
// Note: sendCurrentText does nothing unless mFallbackMode is set
sendCurrentText();
endBatchEdit();
+ endComposingRegionEditInternal();
}
return true;
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index 5ac878d88100..592993cc3d3e 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -424,7 +424,7 @@ public class UiTranslationController {
if (callback == null) {
if (view instanceof TextView) {
// developer doesn't provide their override, we set the default TextView
- // implememtation.
+ // implementation.
callback = new TextViewTranslationCallback();
view.setViewTranslationCallback(callback);
} else {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3c4fd5e93580..37374ef37ada 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -129,7 +129,6 @@ import android.text.method.TextKeyListener;
import android.text.method.TimeKeyListener;
import android.text.method.TransformationMethod;
import android.text.method.TransformationMethod2;
-import android.text.method.TranslationTransformationMethod;
import android.text.method.WordIterator;
import android.text.style.CharacterStyle;
import android.text.style.ClickableSpan;
@@ -199,7 +198,6 @@ import android.view.translation.TranslationSpec;
import android.view.translation.UiTranslationController;
import android.view.translation.ViewTranslationCallback;
import android.view.translation.ViewTranslationRequest;
-import android.view.translation.ViewTranslationResponse;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.annotations.VisibleForTesting;
@@ -10832,11 +10830,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ notifyContentCaptureTextChanged();
+ }
+
+ /**
+ * Notifies the ContentCapture service that the text of the view has changed (only if
+ * ContentCapture has been notified of this view's existence already).
+ *
+ * @hide
+ */
+ public void notifyContentCaptureTextChanged() {
// TODO(b/121045053): should use a flag / boolean to keep status of SHOWN / HIDDEN instead
// of using isLaidout(), so it's not called in cases where it's laid out but a
// notifyAppeared was not sent.
-
- // ContentCapture
if (isLaidOut() && isImportantForContentCapture() && getNotifiedContentCaptureAppeared()) {
final ContentCaptureManager cm = mContext.getSystemService(ContentCaptureManager.class);
if (cm != null && cm.isContentCaptureEnabled()) {
@@ -13925,8 +13931,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Log.w(LOG_TAG, "Cannot create translation request. editable = "
+ isTextEditable() + ", isPassword = " + isPassword + ", selectable = "
+ isTextSelectable());
- return;
}
+ return;
}
// TODO(b/176488462): apply the view's important for translation
requestBuilder.setValue(ViewTranslationRequest.ID_TEXT,
@@ -13938,33 +13944,4 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
requestsCollector.accept(requestBuilder.build());
}
-
- /**
- *
- * Called when the content from {@link #onCreateViewTranslationRequest} had been translated by
- * the TranslationService. The default implementation will replace the current
- * {@link TransformationMethod} to transform the original text to the translated text display.
- *
- * @param response a {@link ViewTranslationResponse} that contains the translated information
- * which can be shown in the view.
- */
- @Override
- public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) {
- // set ViewTranslationResponse
- super.onViewTranslationResponse(response);
- // TODO(b/178353965): move to ViewTranslationCallback.onShow()
- ViewTranslationCallback callback = getViewTranslationCallback();
- if (callback instanceof TextViewTranslationCallback) {
- TextViewTranslationCallback textViewDefaultCallback =
- (TextViewTranslationCallback) callback;
- TranslationTransformationMethod oldTranslationMethod =
- textViewDefaultCallback.getTranslationTransformation();
- TransformationMethod originalTranslationMethod = oldTranslationMethod != null
- ? oldTranslationMethod.getOriginalTransformationMethod() : mTransformation;
- TranslationTransformationMethod newTranslationMethod =
- new TranslationTransformationMethod(response, originalTranslationMethod);
- // TODO(b/178353965): well-handle setTransformationMethod.
- textViewDefaultCallback.setTranslationTransformation(newTranslationMethod);
- }
- }
}
diff --git a/core/java/android/widget/TextViewTranslationCallback.java b/core/java/android/widget/TextViewTranslationCallback.java
index a7d5ee465299..e1b04f8957e5 100644
--- a/core/java/android/widget/TextViewTranslationCallback.java
+++ b/core/java/android/widget/TextViewTranslationCallback.java
@@ -56,26 +56,6 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
private CharSequence mContentDescription;
- /**
- * Invoked by the platform when receiving the successful {@link ViewTranslationResponse} for the
- * view that provides the translatable information by {@link View#createTranslationRequest} and
- * sent by the platform.
- */
- void setTranslationTransformation(TranslationTransformationMethod method) {
- if (method == null) {
- if (DEBUG) {
- Log.w(TAG, "setTranslationTransformation: should not set null "
- + "TranslationTransformationMethod");
- }
- return;
- }
- mTranslationTransformation = method;
- }
-
- TranslationTransformationMethod getTranslationTransformation() {
- return mTranslationTransformation;
- }
-
private void clearTranslationTransformation() {
if (DEBUG) {
Log.v(TAG, "clearTranslationTransformation: " + mTranslationTransformation);
@@ -88,34 +68,33 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
*/
@Override
public boolean onShowTranslation(@NonNull View view) {
- if (view.getViewTranslationResponse() == null) {
- Log.wtf(TAG, "onShowTranslation() shouldn't be called before "
+ ViewTranslationResponse response = view.getViewTranslationResponse();
+ if (response == null) {
+ Log.e(TAG, "onShowTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
- if (mTranslationTransformation != null) {
- final TransformationMethod transformation = mTranslationTransformation;
- runWithAnimation(
- (TextView) view,
- () -> {
- mIsShowingTranslation = true;
- ((TextView) view).setTransformationMethod(transformation);
- });
- ViewTranslationResponse response = view.getViewTranslationResponse();
- if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
- CharSequence translatedContentDescription =
- response.getValue(ViewTranslationRequest.ID_CONTENT_DESCRIPTION).getText();
- if (!TextUtils.isEmpty(translatedContentDescription)) {
- mContentDescription = view.getContentDescription();
- view.setContentDescription(translatedContentDescription);
- }
- }
- } else {
- if (DEBUG) {
- // TODO(b/182433547): remove before S release
- Log.w(TAG, "onShowTranslation(): no translated text.");
+ if (mTranslationTransformation == null) {
+ TransformationMethod originalTranslationMethod =
+ ((TextView) view).getTransformationMethod();
+ mTranslationTransformation = new TranslationTransformationMethod(response,
+ originalTranslationMethod);
+ }
+ final TransformationMethod transformation = mTranslationTransformation;
+ runWithAnimation(
+ (TextView) view,
+ () -> {
+ mIsShowingTranslation = true;
+ // TODO(b/178353965): well-handle setTransformationMethod.
+ ((TextView) view).setTransformationMethod(transformation);
+ });
+ if (response.getKeys().contains(ViewTranslationRequest.ID_CONTENT_DESCRIPTION)) {
+ CharSequence translatedContentDescription =
+ response.getValue(ViewTranslationRequest.ID_CONTENT_DESCRIPTION).getText();
+ if (!TextUtils.isEmpty(translatedContentDescription)) {
+ mContentDescription = view.getContentDescription();
+ view.setContentDescription(translatedContentDescription);
}
- return false;
}
return true;
}
@@ -126,7 +105,7 @@ public class TextViewTranslationCallback implements ViewTranslationCallback {
@Override
public boolean onHideTranslation(@NonNull View view) {
if (view.getViewTranslationResponse() == null) {
- Log.wtf(TAG, "onHideTranslation() shouldn't be called before "
+ Log.e(TAG, "onHideTranslation() shouldn't be called before "
+ "onViewTranslationResponse().");
return false;
}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 4a3bf91645f2..148986a558e7 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -292,6 +292,7 @@ public final class SplashScreenView extends FrameLayout {
private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
final SurfaceView surfaceView = new SurfaceView(view.getContext());
+ surfaceView.setPadding(0, 0, 0, 0);
if (mSurfacePackage == null) {
if (DEBUG) {
Log.d(TAG,
diff --git a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
index ec99c95a737c..d0214e6e0082 100644
--- a/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
+++ b/core/java/com/android/internal/app/IHotwordRecognitionStatusCallback.aidl
@@ -78,4 +78,7 @@ oneway interface IHotwordRecognitionStatusCallback {
* @param status The status about the result of requesting update state action.
*/
void onStatusReported(int status);
+
+ /** Called when the hotword detection process is restarted */
+ void onProcessRestarted();
}
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index af21f8183d3a..9ced6097804d 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -228,7 +228,7 @@ public interface ServiceConnector<I extends IInterface> {
private final int mBindingFlags;
private final @Nullable Function<IBinder, I> mBinderAsInterface;
private final @NonNull Handler mHandler;
- private final @NonNull Executor mExecutor;
+ protected final @NonNull Executor mExecutor;
private volatile I mService = null;
private boolean mBinding = false;
diff --git a/core/java/com/android/internal/os/AppZygoteInit.java b/core/java/com/android/internal/os/AppZygoteInit.java
index 0e83e41a7423..f925afc2a921 100644
--- a/core/java/com/android/internal/os/AppZygoteInit.java
+++ b/core/java/com/android/internal/os/AppZygoteInit.java
@@ -91,7 +91,9 @@ class AppZygoteInit {
} else {
Constructor<?> ctor = cl.getConstructor();
ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
+ Zygote.markOpenedFilesBeforePreload();
preloadObject.doPreload(appInfo);
+ Zygote.allowFilesOpenedByPreload();
}
} catch (ReflectiveOperationException e) {
Log.e(TAG, "AppZygote application preload failed for "
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 4f2f973b51b1..dfd561a8cc30 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -23,7 +23,10 @@ import java.util.List;
/**
* Contains power usage of an application, system service, or hardware type.
+ *
+ * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
*/
+@Deprecated
public class BatterySipper implements Comparable<BatterySipper> {
@UnsupportedAppUsage
public int userId;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b20f50d62de4..608782a39f6b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -59,7 +59,10 @@ import java.util.List;
*
* The caller must initialize this class as soon as activity object is ready to use (for example, in
* onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
+ *
+ * @deprecated Please use BatteryStatsManager.getBatteryUsageStats instead.
*/
+@Deprecated
public class BatteryStatsHelper {
static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 945a6ab11856..dab3e9fa15fa 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12141,6 +12141,15 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
}
+
+ void reset() {
+ idleTimeMs = 0;
+ rxTimeMs = 0;
+ txTimeMs = 0;
+ energy = 0;
+ uidRxBytes.clear();
+ uidTxBytes.clear();
+ }
}
private final BluetoothActivityInfoCache mLastBluetoothActivityInfo
@@ -12167,6 +12176,15 @@ public class BatteryStatsImpl extends BatteryStats {
mHasBluetoothReporting = true;
+ if (info.getControllerRxTimeMillis() < mLastBluetoothActivityInfo.rxTimeMs
+ || info.getControllerTxTimeMillis() < mLastBluetoothActivityInfo.txTimeMs
+ || info.getControllerIdleTimeMillis() < mLastBluetoothActivityInfo.idleTimeMs
+ || info.getControllerEnergyUsed() < mLastBluetoothActivityInfo.energy) {
+ // A drop in accumulated Bluetooth stats is a sign of a Bluetooth crash.
+ // Reset the preserved previous snapshot in order to restart accumulating deltas.
+ mLastBluetoothActivityInfo.reset();
+ }
+
final long rxTimeMs =
info.getControllerRxTimeMillis() - mLastBluetoothActivityInfo.rxTimeMs;
final long txTimeMs =
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 0c9dded42bda..e4e28a926ed6 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -500,6 +500,36 @@ public final class Zygote {
}
/**
+ * Scans file descriptors in /proc/self/fd/, stores their metadata from readlink(2)/stat(2) when
+ * available. Saves this information in a global on native side, to be used by subsequent call
+ * to allowFilesOpenedByPreload(). Fatally fails if the FDs are of unsupported type and are not
+ * explicitly allowed. Ignores repeated invocations.
+ *
+ * Inspecting the FDs is more permissive than in forkAndSpecialize() because preload is invoked
+ * earlier and hence needs to allow a few open sockets. The checks in forkAndSpecialize()
+ * enforce that these sockets are closed when forking.
+ */
+ static void markOpenedFilesBeforePreload() {
+ nativeMarkOpenedFilesBeforePreload();
+ }
+
+ private static native void nativeMarkOpenedFilesBeforePreload();
+
+ /**
+ * By scanning /proc/self/fd/ determines file descriptor numbers in this process opened since
+ * the first call to markOpenedFilesBeforePreload(). These FDs are treated as 'owned' by the
+ * custom preload of the App Zygote - the app is responsible for not sharing data with its other
+ * processes using these FDs, including by lseek(2). File descriptor types and file names are
+ * not checked. Changes in FDs recorded by markOpenedFilesBeforePreload() are not expected and
+ * kill the current process.
+ */
+ static void allowFilesOpenedByPreload() {
+ nativeAllowFilesOpenedByPreload();
+ }
+
+ private static native void nativeAllowFilesOpenedByPreload();
+
+ /**
* Installs a seccomp filter that limits setresuid()/setresgid() to the passed-in range
* @param uidGidMin The smallest allowed uid/gid
* @param uidGidMax The largest allowed uid/gid
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 1a23cc11fca8..134b1587ee58 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -70,12 +70,12 @@ import android.transition.TransitionInflater;
import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.AndroidRuntimeException;
-import android.view.AttachedSurfaceControl;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.view.AttachedSurfaceControl;
import android.view.ContextThemeWrapper;
import android.view.CrossWindowBlurListeners;
import android.view.Gravity;
@@ -3148,7 +3148,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (cb == null || isDestroyed()) {
result = false;
} else {
- sendCloseSystemWindows("search");
int deviceId = event.getDeviceId();
SearchEvent searchEvent = null;
if (deviceId != 0) {
diff --git a/core/java/com/android/internal/util/function/DodecConsumer.java b/core/java/com/android/internal/util/function/DodecConsumer.java
new file mode 100644
index 000000000000..b4d2fb94d245
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Consumer;
+
+
+/**
+ * A 12-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface DodecConsumer<A, B, C, D, E, F, G, H, I, J, K, L> {
+ void accept(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecFunction.java b/core/java/com/android/internal/util/function/DodecFunction.java
new file mode 100644
index 000000000000..178b2c111fd7
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecFunction.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Function;
+
+/**
+ * A 12-argument {@link Function}
+ *
+ * @hide
+ */
+public interface DodecFunction<A, B, C, D, E, F, G, H, I, J, K, L, R> {
+ R apply(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/DodecPredicate.java b/core/java/com/android/internal/util/function/DodecPredicate.java
new file mode 100644
index 000000000000..d3a2b856100f
--- /dev/null
+++ b/core/java/com/android/internal/util/function/DodecPredicate.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util.function;
+
+import java.util.function.Predicate;
+
+/**
+ * A 12-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface DodecPredicate<A, B, C, D, E, F, G, H, I, J, K, L> {
+ boolean test(A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l);
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
index a60cc0fb101f..f073c1c046c5 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -23,6 +23,8 @@ import android.os.Message;
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HexConsumer;
@@ -188,7 +190,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -205,7 +207,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -222,7 +224,7 @@ public interface PooledLambda {
A arg1) {
return acquire(PooledLambdaImpl.sPool,
function, 1, 0, ReturnType.OBJECT, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -253,7 +255,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 1, 0, ReturnType.VOID, arg1, null, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -273,7 +275,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -291,7 +293,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -309,7 +311,7 @@ public interface PooledLambda {
A arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -327,7 +329,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -345,7 +347,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -364,7 +366,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -384,7 +386,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -405,7 +407,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -423,7 +425,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -441,7 +443,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -459,7 +461,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -477,7 +479,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2) {
return acquire(PooledLambdaImpl.sPool,
function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -509,7 +511,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 2, 0, ReturnType.VOID, arg1, arg2, null, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -530,7 +532,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -549,7 +551,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -568,7 +570,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -587,7 +589,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -606,7 +608,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -625,7 +627,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -644,7 +646,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -663,7 +665,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
return acquire(PooledLambdaImpl.sPool,
function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -696,7 +698,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -718,7 +720,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -738,7 +740,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -758,7 +760,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -778,7 +780,7 @@ public interface PooledLambda {
ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -798,7 +800,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -818,7 +820,7 @@ public interface PooledLambda {
A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -838,7 +840,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -858,7 +860,7 @@ public interface PooledLambda {
A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -878,7 +880,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -898,7 +900,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
return acquire(PooledLambdaImpl.sPool,
function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -932,7 +934,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, null, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -955,7 +957,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -976,7 +978,7 @@ public interface PooledLambda {
function, A arg1, B arg2, C arg3, D arg4, E arg5) {
return acquire(PooledLambdaImpl.sPool,
function, 5, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1012,7 +1014,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 5, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, null, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1036,7 +1038,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1058,7 +1060,7 @@ public interface PooledLambda {
? extends R> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6) {
return acquire(PooledLambdaImpl.sPool,
function, 6, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1095,7 +1097,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 6, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, null, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1120,7 +1122,7 @@ public interface PooledLambda {
? super G> function, A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1144,7 +1146,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7) {
return acquire(PooledLambdaImpl.sPool,
function, 7, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1182,7 +1184,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 7, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, null,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1209,7 +1211,7 @@ public interface PooledLambda {
H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1234,7 +1236,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8) {
return acquire(PooledLambdaImpl.sPool,
function, 8, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
}
/**
@@ -1274,7 +1276,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 8, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- null, null, null);
+ null, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1302,7 +1304,7 @@ public interface PooledLambda {
E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1328,7 +1330,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9) {
return acquire(PooledLambdaImpl.sPool,
function, 9, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
}
/**
@@ -1369,7 +1371,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 9, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, null, null);
+ arg9, null, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1398,7 +1400,7 @@ public interface PooledLambda {
D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1425,7 +1427,7 @@ public interface PooledLambda {
A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10) {
return acquire(PooledLambdaImpl.sPool,
function, 10, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, null);
+ arg9, arg10, null, null);
}
/**
@@ -1467,7 +1469,7 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 10, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, null);
+ arg8, arg9, arg10, null, null);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
@@ -1498,7 +1500,7 @@ public interface PooledLambda {
C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10, K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1528,7 +1530,7 @@ public interface PooledLambda {
K arg11) {
return acquire(PooledLambdaImpl.sPool,
function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
- arg9, arg10, arg11);
+ arg9, arg10, arg11, null);
}
/**
@@ -1571,7 +1573,118 @@ public interface PooledLambda {
synchronized (Message.sPoolSync) {
PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
- arg8, arg9, arg10, arg11);
+ arg8, arg9, arg10, arg11, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11, arg12) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> PooledRunnable obtainRunnable(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K,
+ ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 12, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10,
+ * arg11) }
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L, R> PooledSupplier<R> obtainSupplier(
+ DodecFunction<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? extends L,
+ ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 11, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
+ arg9, arg10, arg11, arg12);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuintConsumer, Object, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @param arg5 parameter supplied to {@code function} on call
+ * @param arg6 parameter supplied to {@code function} on call
+ * @param arg7 parameter supplied to {@code function} on call
+ * @param arg8 parameter supplied to {@code function} on call
+ * @param arg9 parameter supplied to {@code function} on call
+ * @param arg10 parameter supplied to {@code function} on call
+ * @param arg11 parameter supplied to {@code function} on call
+ * @param arg12 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4, arg5, arg6,
+ * arg7, arg8, arg9, arg10, arg11) } when handled
+ */
+ static <A, B, C, D, E, F, G, H, I, J, K, L> Message obtainMessage(
+ DodecConsumer<? super A, ? super B, ? super C, ? super D, ? super E, ? super F,
+ ? super G, ? super H, ? super I, ? super J, ? super K, ? super L> function,
+ A arg1, B arg2, C arg3, D arg4, E arg5, F arg6, G arg7, H arg8, I arg9, J arg10,
+ K arg11, L arg12) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 11, 0, ReturnType.VOID, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9, arg10, arg11, arg12);
return Message.obtain().setCallback(callback.recycleOnUse());
}
}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 1646a07b8001..19f0816e3e48 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -28,6 +28,9 @@ import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.function.DecConsumer;
import com.android.internal.util.function.DecFunction;
import com.android.internal.util.function.DecPredicate;
+import com.android.internal.util.function.DodecConsumer;
+import com.android.internal.util.function.DodecFunction;
+import com.android.internal.util.function.DodecPredicate;
import com.android.internal.util.function.HeptConsumer;
import com.android.internal.util.function.HeptFunction;
import com.android.internal.util.function.HeptPredicate;
@@ -458,6 +461,28 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
}
}
} break;
+
+ case 12: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((DodecConsumer) mFunc).accept(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((DodecPredicate) mFunc).test(popArg(0),
+ popArg(1), popArg(2), popArg(3), popArg(4),
+ popArg(5), popArg(6), popArg(7), popArg(8), popArg(9), popArg(10),
+ popArg(11));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((DodecFunction) mFunc).apply(popArg(0), popArg(1),
+ popArg(2), popArg(3), popArg(4), popArg(5),
+ popArg(6), popArg(7), popArg(8), popArg(9), popArg(10), popArg(11));
+ }
+ }
+ } break;
}
throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
}
@@ -523,7 +548,8 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
*/
static <E extends PooledLambda> E acquire(Pool pool, Object func,
int fNumArgs, int numPlaceholders, int fReturnType, Object a, Object b, Object c,
- Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k) {
+ Object d, Object e, Object f, Object g, Object h, Object i, Object j, Object k,
+ Object l) {
PooledLambdaImpl r = acquire(pool);
if (DEBUG) {
Log.i(LOG_TAG,
@@ -543,6 +569,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
+ ", i = " + i
+ ", j = " + j
+ ", k = " + k
+ + ", l = " + l
+ ")");
}
r.mFunc = Objects.requireNonNull(func);
@@ -560,6 +587,7 @@ final class PooledLambdaImpl<R> extends OmniFunction<Object,
setIfInBounds(r.mArgs, 8, i);
setIfInBounds(r.mArgs, 9, j);
setIfInBounds(r.mArgs, 10, k);
+ setIfInBounds(r.mArgs, 11, l);
return (E) r;
}
diff --git a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
index 8aa2d57e8ea6..9e09006f608d 100644
--- a/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
+++ b/core/java/com/android/internal/view/ScrollCaptureViewSupport.java
@@ -198,12 +198,9 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
private static final float LIGHT_RADIUS_DP = 800;
private static final String TAG = "ViewRenderer";
- private HardwareRenderer mRenderer;
- private RenderNode mCaptureRenderNode;
- private final RectF mTempRectF = new RectF();
- private final Rect mSourceRect = new Rect();
+ private final HardwareRenderer mRenderer;
+ private final RenderNode mCaptureRenderNode;
private final Rect mTempRect = new Rect();
- private final Matrix mTempMatrix = new Matrix();
private final int[] mTempLocation = new int[2];
private long mLastRenderedSourceDrawingId = -1;
private Surface mSurface;
@@ -313,11 +310,9 @@ public class ScrollCaptureViewSupport<V extends View> implements ScrollCaptureCa
}
private void transformToRoot(View local, Rect localRect, Rect outRect) {
- mTempMatrix.reset();
- local.transformMatrixToGlobal(mTempMatrix);
- mTempRectF.set(localRect);
- mTempMatrix.mapRect(mTempRectF);
- mTempRectF.round(outRect);
+ local.getLocationInWindow(mTempLocation);
+ outRect.set(localRect);
+ outRect.offset(mTempLocation[0], mTempLocation[1]);
}
public void setColorMode(@ColorMode int colorMode) {
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 4a70f7416075..299cbe12b4d1 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -257,7 +257,7 @@ public class CachingIconView extends ImageView {
boolean hasColor = color != ColoredIconHelper.COLOR_INVALID;
if (background == null) {
// This is the pre-S style -- colored icon with no background.
- if (hasColor) {
+ if (hasColor && icon != null) {
icon.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
} else {
@@ -265,7 +265,9 @@ public class CachingIconView extends ImageView {
// colorize the icon itself with the background color, creating an inverted effect.
if (hasColor) {
background.mutate().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
- icon.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
+ if (icon != null) {
+ icon.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
+ }
} else {
background.mutate().setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
}
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 3d054a5e773c..02ffe8c5268e 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -99,6 +99,12 @@ public class EditableInputConnection extends BaseInputConnection
}
@Override
+ public void endComposingRegionEditInternal() {
+ // The ContentCapture service is interested in Composing-state changes.
+ mTextView.notifyContentCaptureTextChanged();
+ }
+
+ @Override
public void closeConnection() {
super.closeConnection();
synchronized(this) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 73c5460755b1..3f756d757706 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -1524,7 +1524,9 @@ public class LockPatternView extends View {
if (virtualViewId != ExploreByTouchHelper.INVALID_ID) {
int row = (virtualViewId - VIRTUAL_BASE_VIEW_ID) / 3;
int col = (virtualViewId - VIRTUAL_BASE_VIEW_ID) % 3;
- return !mPatternDrawLookup[row][col];
+ if (row < 3) {
+ return !mPatternDrawLookup[row][col];
+ }
}
return false;
}
@@ -1570,7 +1572,6 @@ public class LockPatternView extends View {
final Rect bounds = mTempRect;
final int row = ordinal / 3;
final int col = ordinal % 3;
- final CellState cell = mCellStates[row][col];
float centerX = getCenterXForColumn(col);
float centerY = getCenterYForRow(row);
float cellheight = mSquareHeight * mHitFactor * 0.5f;
diff --git a/core/java/com/android/server/AppWidgetBackupBridge.java b/core/java/com/android/server/AppWidgetBackupBridge.java
index 7d82d355e3eb..8e834a87784d 100644
--- a/core/java/com/android/server/AppWidgetBackupBridge.java
+++ b/core/java/com/android/server/AppWidgetBackupBridge.java
@@ -47,9 +47,9 @@ public class AppWidgetBackupBridge {
: null;
}
- public static void restoreStarting(int userId) {
+ public static void systemRestoreStarting(int userId) {
if (sAppWidgetService != null) {
- sAppWidgetService.restoreStarting(userId);
+ sAppWidgetService.systemRestoreStarting(userId);
}
}
@@ -59,9 +59,9 @@ public class AppWidgetBackupBridge {
}
}
- public static void restoreFinished(int userId) {
+ public static void systemRestoreFinished(int userId) {
if (sAppWidgetService != null) {
- sAppWidgetService.restoreFinished(userId);
+ sAppWidgetService.systemRestoreFinished(userId);
}
}
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index bd0de2984b7f..a8dcbaffeeb5 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -86,6 +86,7 @@ public class SystemConfig {
// and "allow-ignore-location-settings".
private static final int ALLOW_OVERRIDE_APP_RESTRICTIONS = 0x100;
private static final int ALLOW_IMPLICIT_BROADCASTS = 0x200;
+ private static final int ALLOW_VENDOR_APEX = 0x400;
private static final int ALLOW_ALL = ~0;
// property for runtime configuration differentiation
@@ -240,6 +241,7 @@ public class SystemConfig {
private final ArraySet<String> mRollbackWhitelistedPackages = new ArraySet<>();
private final ArraySet<String> mWhitelistedStagedInstallers = new ArraySet<>();
+ private final ArraySet<String> mAllowedVendorApexes = new ArraySet<>();
/**
* Map of system pre-defined, uniquely named actors; keys are namespace,
@@ -410,6 +412,10 @@ public class SystemConfig {
return mWhitelistedStagedInstallers;
}
+ public Set<String> getAllowedVendorApexes() {
+ return mAllowedVendorApexes;
+ }
+
public ArraySet<String> getAppDataIsolationWhitelistedApps() {
return mAppDataIsolationWhitelistedApps;
}
@@ -484,7 +490,7 @@ public class SystemConfig {
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
- | ALLOW_ASSOCIATIONS;
+ | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
@@ -525,7 +531,8 @@ public class SystemConfig {
}
// Allow OEM to customize these
- int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
+ int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS
+ | ALLOW_VENDOR_APEX;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
@@ -536,7 +543,8 @@ public class SystemConfig {
// the use of hidden APIs from the product partition.
int productPermissionFlag = ALLOW_FEATURES | ALLOW_LIBS | ALLOW_PERMISSIONS
| ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS | ALLOW_HIDDENAPI_WHITELISTING
- | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS;
+ | ALLOW_ASSOCIATIONS | ALLOW_OVERRIDE_APP_RESTRICTIONS | ALLOW_IMPLICIT_BROADCASTS
+ | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.R) {
// TODO(b/157393157): This must check product interface enforcement instead of
// DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement.
@@ -663,6 +671,7 @@ public class SystemConfig {
(permissionFlag & ALLOW_OVERRIDE_APP_RESTRICTIONS) != 0;
final boolean allowImplicitBroadcasts = (permissionFlag & ALLOW_IMPLICIT_BROADCASTS)
!= 0;
+ final boolean allowVendorApex = (permissionFlag & ALLOW_VENDOR_APEX) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -1212,6 +1221,20 @@ public class SystemConfig {
}
XmlUtils.skipCurrentTag(parser);
} break;
+ case "allowed-vendor-apex": {
+ if (allowVendorApex) {
+ String pkgName = parser.getAttributeValue(null, "package");
+ if (pkgName == null) {
+ Slog.w(TAG, "<" + name + "> without package in " + permFile
+ + " at " + parser.getPositionDescription());
+ } else {
+ mAllowedVendorApexes.add(pkgName);
+ }
+ } else {
+ logNotAllowedInPartition(name, permFile, parser);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ } break;
default: {
Slog.w(TAG, "Tag " + name + " is unknown in "
+ permFile + " at " + parser.getPositionDescription());
diff --git a/core/java/com/android/server/WidgetBackupProvider.java b/core/java/com/android/server/WidgetBackupProvider.java
index a2efbdd6f2f8..5453c4de6986 100644
--- a/core/java/com/android/server/WidgetBackupProvider.java
+++ b/core/java/com/android/server/WidgetBackupProvider.java
@@ -28,7 +28,7 @@ import java.util.List;
public interface WidgetBackupProvider {
public List<String> getWidgetParticipants(int userId);
public byte[] getWidgetState(String packageName, int userId);
- public void restoreStarting(int userId);
+ public void systemRestoreStarting(int userId);
public void restoreWidgetState(String packageName, byte[] restoredState, int userId);
- public void restoreFinished(int userId);
+ public void systemRestoreFinished(int userId);
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d528428a0e83..e9e79dc30c20 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -1775,6 +1775,16 @@ static jint nativeGetGPUContextPriority(JNIEnv* env, jclass clazz) {
return static_cast<jint>(SurfaceComposerClient::getGPUContextPriority());
}
+static void nativeSetTransformHint(JNIEnv* env, jclass clazz, jlong nativeSurfaceControl,
+ jint transformHint) {
+ sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl*>(nativeSurfaceControl));
+ if (surface == nullptr) {
+ return;
+ }
+ surface->setTransformHint(
+ ui::Transform::toRotationFlags(static_cast<ui::Rotation>(transformHint)));
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1962,6 +1972,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeCreateJankDataListenerWrapper },
{"nativeGetGPUContextPriority", "()I",
(void*)nativeGetGPUContextPriority },
+ {"nativeSetTransformHint", "(JI)V",
+ (void*)nativeSetTransformHint },
// clang-format on
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4a1a2728b987..502849e4824a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -27,9 +27,11 @@
#include <sys/types.h>
#include <dirent.h>
+#include <algorithm>
#include <array>
#include <atomic>
#include <functional>
+#include <iterator>
#include <list>
#include <optional>
#include <sstream>
@@ -2005,6 +2007,9 @@ void zygote::ZygoteFailure(JNIEnv* env,
__builtin_unreachable();
}
+static std::set<int>* gPreloadFds = nullptr;
+static bool gPreloadFdsExtracted = false;
+
// Utility routine to fork a process from the zygote.
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
@@ -2030,9 +2035,12 @@ pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
__android_log_close();
AStatsSocket_close();
- // If this is the first fork for this zygote, create the open FD table. If
- // it isn't, we just need to check whether the list of open files has changed
- // (and it shouldn't in the normal case).
+ // If this is the first fork for this zygote, create the open FD table,
+ // verifying that files are of supported type and allowlisted. Otherwise (not
+ // the first fork), check that the open files have not changed. Newly open
+ // files are not expected, and will be disallowed in the future. Currently
+ // they are allowed if they pass the same checks as in the
+ // FileDescriptorTable::Create() above.
if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
} else {
@@ -2128,7 +2136,12 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
fds_to_ignore.push_back(gSystemServerSocketFd);
}
- pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
+ if (gPreloadFds && gPreloadFdsExtracted) {
+ fds_to_ignore.insert(fds_to_ignore.end(), gPreloadFds->begin(), gPreloadFds->end());
+ }
+
+ pid_t pid = zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
+ true);
if (pid == 0) {
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities,
@@ -2265,6 +2278,10 @@ int zygote::forkApp(JNIEnv* env,
}
fds_to_ignore.push_back(gSystemServerSocketFd);
}
+ if (gPreloadFds && gPreloadFdsExtracted) {
+ fds_to_ignore.insert(fds_to_ignore.end(), gPreloadFds->begin(), gPreloadFds->end());
+ }
+
return zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close,
fds_to_ignore, is_priority_fork == JNI_TRUE, purge);
}
@@ -2568,6 +2585,35 @@ static jint com_android_internal_os_Zygote_nativeCurrentTaggingLevel(JNIEnv* env
#endif // defined(__aarch64__)
}
+static void com_android_internal_os_Zygote_nativeMarkOpenedFilesBeforePreload(JNIEnv* env, jclass) {
+ // Ignore invocations when too early or too late.
+ if (gPreloadFds) {
+ return;
+ }
+
+ // App Zygote Preload starts soon. Save FDs remaining open. After the
+ // preload finishes newly open files will be determined.
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "zygote", nullptr, _1);
+ gPreloadFds = GetOpenFds(fail_fn).release();
+}
+
+static void com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload(JNIEnv* env, jclass) {
+ // Ignore invocations when too early or too late.
+ if (!gPreloadFds || gPreloadFdsExtracted) {
+ return;
+ }
+
+ // Find the newly open FDs, if any.
+ auto fail_fn = std::bind(zygote::ZygoteFailure, env, "zygote", nullptr, _1);
+ std::unique_ptr<std::set<int>> current_fds = GetOpenFds(fail_fn);
+ auto difference = std::make_unique<std::set<int>>();
+ std::set_difference(current_fds->begin(), current_fds->end(), gPreloadFds->begin(),
+ gPreloadFds->end(), std::inserter(*difference, difference->end()));
+ delete gPreloadFds;
+ gPreloadFds = difference.release();
+ gPreloadFdsExtracted = true;
+}
+
static const JNINativeMethod gMethods[] = {
{"nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
@@ -2616,6 +2662,10 @@ static const JNINativeMethod gMethods[] = {
(void*)com_android_internal_os_Zygote_nativeSupportsTaggedPointers},
{"nativeCurrentTaggingLevel", "()I",
(void*)com_android_internal_os_Zygote_nativeCurrentTaggingLevel},
+ {"nativeMarkOpenedFilesBeforePreload", "()V",
+ (void*)com_android_internal_os_Zygote_nativeMarkOpenedFilesBeforePreload},
+ {"nativeAllowFilesOpenedByPreload", "()V",
+ (void*)com_android_internal_os_Zygote_nativeAllowFilesOpenedByPreload},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 7fa627b3f809..6f5cc5314d0b 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -52,7 +52,6 @@ static const char* kPathAllowlist[] = {
static const char kFdPath[] = "/proc/self/fd";
-// static
FileDescriptorAllowlist* FileDescriptorAllowlist::Get() {
if (instance_ == nullptr) {
instance_ = new FileDescriptorAllowlist();
@@ -169,8 +168,8 @@ class FileDescriptorInfo {
// Create a FileDescriptorInfo for a given file descriptor.
static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
- // Checks whether the file descriptor associated with this object
- // refers to the same description.
+ // Checks whether the file descriptor associated with this object refers to
+ // the same description.
bool RefersToSameFile() const;
void ReopenOrDetach(fail_fn_t fail_fn) const;
@@ -185,8 +184,10 @@ class FileDescriptorInfo {
const bool is_sock;
private:
+ // Constructs for sockets.
explicit FileDescriptorInfo(int fd);
+ // Constructs for non-socket file descriptors.
FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
int fd_flags, int fs_flags, off_t offset);
@@ -204,7 +205,6 @@ class FileDescriptorInfo {
DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
};
-// static
FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
struct stat f_stat;
// This should never happen; the zygote should always have the right set
@@ -465,42 +465,24 @@ void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
}
}
-// static
+// TODO: Move the definitions here and eliminate the forward declarations. They
+// temporarily help making code reviews easier.
+static int ParseFd(dirent* dir_entry, int dir_fd);
+static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
+ fail_fn_t fail_fn);
+
FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
fail_fn_t fail_fn) {
- DIR* proc_fd_dir = opendir(kFdPath);
- if (proc_fd_dir == nullptr) {
- fail_fn(std::string("Unable to open directory ").append(kFdPath));
- }
-
- int dir_fd = dirfd(proc_fd_dir);
- dirent* dir_entry;
-
+ std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
- while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
- const int fd = ParseFd(dir_entry, dir_fd);
- if (fd == -1) {
- continue;
- }
-
- if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
- continue;
- }
-
+ for (auto fd : *open_fds) {
open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
}
-
- if (closedir(proc_fd_dir) == -1) {
- fail_fn("Unable to close directory");
- }
-
return new FileDescriptorTable(open_fd_map);
}
-void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
- std::set<int> open_fds;
-
- // First get the list of open descriptors.
+static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
+ fail_fn_t fail_fn) {
DIR* proc_fd_dir = opendir(kFdPath);
if (proc_fd_dir == nullptr) {
fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
@@ -508,6 +490,7 @@ void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_
strerror(errno)));
}
+ auto result = std::make_unique<std::set<int>>();
int dir_fd = dirfd(proc_fd_dir);
dirent* dir_entry;
while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
@@ -520,14 +503,26 @@ void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_
continue;
}
- open_fds.insert(fd);
+ result->insert(fd);
}
if (closedir(proc_fd_dir) == -1) {
fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
}
+ return result;
+}
+
+std::unique_ptr<std::set<int>> GetOpenFds(fail_fn_t fail_fn) {
+ const std::vector<int> nothing_to_ignore;
+ return GetOpenFdsIgnoring(nothing_to_ignore, fail_fn);
+}
+
+void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
+ std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
- RestatInternal(open_fds, fail_fn);
+ // Check that the files did not change, and leave only newly opened FDs in
+ // |open_fds|.
+ RestatInternal(*open_fds, fail_fn);
}
// Reopens all file descriptors that are contained in the table.
@@ -548,6 +543,12 @@ FileDescriptorTable::FileDescriptorTable(
: open_fd_map_(map) {
}
+FileDescriptorTable::~FileDescriptorTable() {
+ for (auto& it : open_fd_map_) {
+ delete it.second;
+ }
+}
+
void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
// ART creates a file through memfd for optimization purposes. We make sure
// there is at most one being created.
@@ -618,8 +619,7 @@ void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail
}
}
-// static
-int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
+static int ParseFd(dirent* dir_entry, int dir_fd) {
char* end;
const int fd = strtol(dir_entry->d_name, &end, 10);
if ((*end) != '\0') {
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index 14c318e8e84a..a28ebf17d334 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -69,6 +69,9 @@ private:
DISALLOW_COPY_AND_ASSIGN(FileDescriptorAllowlist);
};
+// Returns the set of file descriptors currently open by the process.
+std::unique_ptr<std::set<int>> GetOpenFds(fail_fn_t fail_fn);
+
// A FileDescriptorTable is a collection of FileDescriptorInfo objects
// keyed by their FDs.
class FileDescriptorTable {
@@ -79,6 +82,14 @@ class FileDescriptorTable {
static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
fail_fn_t fail_fn);
+ ~FileDescriptorTable();
+
+ // Checks that the currently open FDs did not change their metadata from
+ // stat(2), readlink(2) etc. Ignores FDs from |fds_to_ignore|.
+ //
+ // Temporary: allows newly open FDs if they pass the same checks as in
+ // Create(). This will be further restricted. See TODOs in the
+ // implementation.
void Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn);
// Reopens all file descriptors that are contained in the table. Returns true
@@ -91,8 +102,6 @@ class FileDescriptorTable {
void RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn);
- static int ParseFd(dirent* e, int dir_fd);
-
// Invariant: All values in this unordered_map are non-NULL.
std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
diff --git a/core/proto/android/server/apphibernationservice.proto b/core/proto/android/server/apphibernationservice.proto
index d341c4b2f0a8..64c2a322548f 100644
--- a/core/proto/android/server/apphibernationservice.proto
+++ b/core/proto/android/server/apphibernationservice.proto
@@ -39,4 +39,5 @@ message GlobalLevelHibernationStatesProto {
message GlobalLevelHibernationStateProto {
optional string package_name = 1;
optional bool hibernated = 2;
+ optional int64 saved_byte = 3;
} \ No newline at end of file
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index e6d724f1ecb2..0b7b49cdea83 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -18,12 +18,15 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
+ android:padding="0dp"
android:orientation="vertical">
<View android:id="@+id/splashscreen_icon_view"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
+ android:padding="0dp"
+ android:background="@null"
android:contentDescription="@string/splash_screen_view_icon_description"/>
<View android:id="@+id/splashscreen_branding_view"
@@ -31,6 +34,8 @@
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="60dp"
+ android:padding="0dp"
+ android:background="@null"
android:contentDescription="@string/splash_screen_view_branding_description"/>
</android.window.SplashScreenView> \ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 803ba649bd29..a285cf7d6edf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer \'n ander vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te helder"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Probeer om dit te verstel"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander elke keer die posisie van jou vinger so effens"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk is gestaaf"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukke is geregistreer nie."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Hierdie toetstel het nie \'n vingerafdruksensor nie."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor is tydelik gedeaktiveer."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor benodig kalibrering"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gebruik vingerafdruk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gebruik vingerafdruk of skermslot"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index e5ef55a2459b..71a07f357b59 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ሌላ የጣት አሻራ ይሞክሩ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"በጣም ብርሃናማ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ለማስተካከል ይሞክሩ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"የጣት አሻራ ትክክለኛነት ተረጋግጧል"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ምንም የጣት አሻራዎች አልተመዘገቡም።"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ይህ መሣሪያ የጣት አሻራ ዳሳሽ የለውም።"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ዳሳሽ ለጊዜው ተሰናክሏል።"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ዳሳሽ ማስተካከልን ይፈልጋል"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ጣት <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"የጣት አሻራ ይጠቀሙ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"የጣት አሻራ ወይም የማያ ገጽ መቆለፊያ ይጠቀሙ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 86a09ee9643b..661001b5448b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -597,6 +597,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"يمكنك تجربة بصمة إصبع أخرى."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"الصورة ساطعة للغاية."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"حاوِل تعديل بصمة الإصبع."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"تم مصادقة بصمة الإصبع"</string>
@@ -613,6 +615,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ليست هناك بصمات إصبع مسجَّلة."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"لا يحتوي هذا الجهاز على مستشعِر بصمات إصبع."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"تم إيقاف جهاز الاستشعار مؤقتًا."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"يحتاج المستشعر إلى المعايرة."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"الإصبع <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استخدام بصمة الإصبع"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استخدام بصمة الإصبع أو قفل الشاشة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 5b2149e92b83..15190e779bd2 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য এটা ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰি চাওক"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অতি উজ্জ্বল"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"মিলাই চাওক"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ফিংগাৰপ্ৰিণ্টৰ সত্যাপন কৰা হ’ল"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনো ফিংগাৰপ্ৰিণ্ট যোগ কৰা নহ\'ল।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইচটোত ফিংগাৰপ্ৰিণ্ট ছেন্সৰ নাই।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ছেন্সৰটো সাময়িকভাৱে অক্ষম হৈ আছে।"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ছেন্সৰৰ কেলিব্ৰেশ্বনৰ প্ৰয়োজন"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> আঙুলি"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 54dc9322417e..25ae5768cd8a 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başqa bir barmaq izini sınayın"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çox işıqlıdır"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Tənzimləməyə çalışın"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmaq izi doğrulandı"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Barmaq izi qeydə alınmayıb."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda barmaq izi sensoru yoxdur."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor müvəqqəti deaktivdir."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor tənzimlənməlidir"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmaq <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmaq izini istifadə edin"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmaq izi və ya ekran kilidindən istifadə edin"</string>
@@ -1624,7 +1627,7 @@
<string name="wireless_display_route_description" msgid="8297563323032966831">"Simsiz ekran"</string>
<string name="media_route_button_content_description" msgid="2299223698196869956">"İştirakçılar"</string>
<string name="media_route_chooser_title" msgid="6646594924991269208">"Cihaza qoş"</string>
- <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Ekranı cihaza yayımla"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Ekran yayımı"</string>
<string name="media_route_chooser_searching" msgid="6119673534251329535">"Cihazlar axtarılır..."</string>
<string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Ayarlar"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Əlaqəni kəsin"</string>
@@ -1695,15 +1698,15 @@
<string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"DEAKTİV"</string>
<string name="accessibility_enable_service_title" msgid="3931558336268541484">"<xliff:g id="SERVICE">%1$s</xliff:g> xidmətinin cihaza tam nəzarət etməsinə icazə verilsin?"</string>
<string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> aktiv olarsa, cihazınız data şifrələnməsini genişləndirmək üçün ekran kilidini istifadə etməyəcək."</string>
- <string name="accessibility_service_warning_description" msgid="291674995220940133">"Tam nəzarət əlçatımlılıq ehtiyaclarınızı ödəyən bəzi tətbiqlər üçün uyğundur."</string>
+ <string name="accessibility_service_warning_description" msgid="291674995220940133">"Tam nəzarət icazəsi xüsusi imkanlara dair yardım edən tətbiqlərə lazımdır, digər tətbiqlərə lazım deyil."</string>
<string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Baxış və nəzarət ekranı"</string>
<string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Ekrandakı bütün kontenti oxuya və kontenti digər tətbiqlərin üzərində göstərə bilər."</string>
<string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Əməliyyatlara baxın və icra edin"</string>
- <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"O, tətbiq və ya avadanlıq sensoru ilə interaktivliyinizi izləyir və əvəzinizdən tətbiqlərlə qarşılıqlı əlaqəyə girir."</string>
+ <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Tətbiq və sensorlarla əlaqələrinizi izləyib tətbiqlərə adınızdan əmrlər verə bilər."</string>
<string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"İcazə verin"</string>
<string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"İmtina edin"</string>
<string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Funksiyanı istifadə etmək üçün onun üzərinə toxunun:"</string>
- <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Əlçatımlılıq düyməsi ilə istifadə edəcəyiniz funksiyaları seçin"</string>
+ <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Xüsusi imkanlar düyməsinin köməyilə işə salınacaq funksiyaları seçin"</string>
<string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Səs səviyyəsi düyməsinin qısayolu ilə istifadə edəcəyiniz funksiyaları seçin"</string>
<string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> deaktiv edilib"</string>
<string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Qısayolları redaktə edin"</string>
@@ -1720,7 +1723,7 @@
<string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Xüsusi imkanlar düyməsinə toxunanda istədiyiniz funksiyanı seçin:"</string>
<string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Əlçatımlılıq jesti (iki barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string>
<string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Əlçatımlılıq jesti (üç barmağınızla ekranın aşağısından yuxarı doğru sürüşdürün) ilə istifadə edəcəyiniz funksiyanı seçin:"</string>
- <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funksiyalar arasında keçid etmək üçün əlçatımlılıq düyməsinə toxunub saxlayın."</string>
+ <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Funksiyalar arasında keçid etmək üçün xüsusi imkanlar düyməsini basıb saxlayın."</string>
<string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Funksiyalar arasında keçid etmək üçün iki barmağınızla yuxarı sürüşdürüb saxlayın."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Funksiyalar arasında keçid etmək üçün üç barmağınızla yuxarı doğru sürüşdürüb saxlayın."</string>
<string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Böyütmə"</string>
@@ -2137,7 +2140,7 @@
<string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Sürətli Ayarlar"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Yandırıb-söndürmə dialoqu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
- <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
+ <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinşot"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Ekranda Əlçatımlılıq Qısayolu"</string>
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" msgid="1057878690209817886">"Ekranda Əlçatımlılıq Qısayolu Seçicisi"</string>
<string name="accessibility_system_action_hardware_a11y_shortcut_label" msgid="5764644187715255107">"Əlçatımlılıq Qısayolu"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ff2289f192bf..ff17bab81413 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probajte sa drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Previše je svetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Probajte da prilagodite"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
@@ -604,6 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registrovan nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzor treba da se kalibriše"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristite otisak prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristite otisak prsta ili zaključavanje ekrana"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index b6ba47a47b1c..a3eebb6b3635 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Паспрабуйце іншы адбітак пальца"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Занадта светла"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Паспрабуйце наладзіць"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Адбітак пальца распазнаны"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Патрабуецца каліброўка датчыка"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Палец <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Выкарыстоўваць адбітак пальца"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Выкарыстоўваць адбітак пальца ці блакіроўку экрана"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 9ab5dfec650a..38fdc499a592 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Опитайте с друг отпечатък"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Твърде светло е"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Опитайте да коригирате"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатъкът е удостоверен"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Няма регистрирани отпечатъци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Това устройство няма сензор за отпечатъци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорът е временно деактивиран."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"За сензора се изисква калибриране"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Пръст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Използване на отпечатък"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Използване на отпечатък или опцията за заключване на екрана"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2a9ecf66d4e9..16ab2247be83 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"অন্য আঙ্গুলের ছাপ দিয়ে চেষ্টা করুন"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"অত্যন্ত উজ্জ্বল"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"অ্যাডজাস্ট করার চেষ্টা করুন"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"আঙ্গুলের ছাপ যাচাই করা হয়েছে"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"কোনও আঙ্গুলের ছাপ নথিভুক্ত করা হয়নি।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"এই ডিভাইসে আঙ্গুলের ছাপ নেওয়ার সেন্সর নেই।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"সেন্সর অস্থায়ীভাবে বন্ধ করা আছে।"</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"আঙ্গুল <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"আঙ্গুলের ছাপ ব্যবহার করুন"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"আঙ্গুলের ছাপ অথবা স্ক্রিন লক ব্যবহার করুন"</string>
@@ -1458,10 +1462,8 @@
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"একটি অ্যাপ্লিকেশানকে প্যাকেজগুলি মুছে দেওয়ার অনুরোধ জানাতে দেয়৷"</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করার জন্য অনুমতি চাওয়া"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"কোনো অ্যাপের জন্য ব্যাটারি অপ্টিমাইজেশন উপেক্ষা করতে সেটিকে অনুমতির চাওয়ার মঞ্জুরি দেয়৷"</string>
- <!-- no translation found for permlab_queryAllPackages (2928450604653281650) -->
- <skip />
- <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) -->
- <skip />
+ <string name="permlab_queryAllPackages" msgid="2928450604653281650">"অন্যান্য সব প্যাকেজের তথ্য সম্পর্কিত কোয়েরি দেখুন"</string>
+ <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"এটি কোনও অ্যাপকে সর্বদা ইনস্টল করা সব প্যাকেজ দেখতে অনুমতি দেয়।"</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্রণের জন্য দুবার ট্যাপ করুন"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"উইজেট যোগ করা যায়নি৷"</string>
<string name="ime_action_go" msgid="5536744546326495436">"যান"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 2d7003b6e4ab..474e861c7aac 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -352,7 +352,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Dozvoljava aplikaciji proširivanje ili sužavanje statusne trake."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"prikaz obavještenja kao aktivnosti preko cijelog ekrana na zaključanom uređaju"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Dozvoljava aplikaciji da prikazuje obavještenja kao aktivnosti preko cijelog ekrana na zaključanom uređaju"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instaliranje prečica"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instaliranje prečica"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Omogućava aplikaciji dodavanje prečice za početni ekran bez intervencije korisnika."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"uklanjanje prečica"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Omogućava aplikaciji uklanjanje prečice početnog ekrana bez intervencije korisnika."</string>
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pokušajte s drugim otiskom prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pokušajte podesiti"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisak prsta je potvrđen"</string>
@@ -604,6 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije prijavljen nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor za otisak prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Potrebno je kalibrirati senzor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Koristi otisak prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Koristi otisak prsta ili zaključavanje ekrana"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 330713d9a6b9..3afb3cb8a01b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova una altra empremta digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hi ha massa llum"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prova d\'ajustar l\'empremta digital"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"L\'empremta digital s\'ha autenticat"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No s\'ha registrat cap empremta digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aquest dispositiu no té sensor d\'empremtes digitals."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor està desactivat temporalment."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Cal calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dit <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilitza l\'empremta digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilitza l\'empremta digital o el bloqueig de pantalla"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c4eb66ea1a3b..07d1060594f2 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -355,7 +355,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Umožňuje aplikaci rozbalit či sbalit stavový řádek."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"zobrazovat oznámení na celé obrazovce zamčeného zařízení"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Umožňuje aplikaci zobrazovat oznámení na celé obrazovce zamčeného zařízení"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instalace zástupců"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instalace zástupců"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Umožňuje aplikaci přidat zástupce na plochu bez zásahu uživatele."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"odinstalace zástupců"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Umožňuje aplikaci odebrat zástupce z plochy bez zásahu uživatele."</string>
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zkuste jiný otisk prstu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Je příliš světlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Zkuste provést úpravu"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Otisk byl ověřen"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nejsou zaregistrovány žádné otisky prstů."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zařízení nemá snímač otisků prstů."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasně deaktivován."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Snímač vyžaduje kalibraci"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použít otisk prstu"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použít otisk prstu nebo zámek obrazovky"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 270848758947..1099af6341ab 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv med et andet fingeraftryk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Der er for lyst"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prøv at justere den"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeraftrykket blev godkendt"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Der er ikke registreret nogen fingeraftryk."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enhed har ingen fingeraftrykslæser."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidigt deaktiveret."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensoren skal kalibreres"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingeraftryk <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Brug fingeraftryk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Brug fingeraftryk eller skærmlås"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 03b9904658d4..000d93ae4d30 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Anderen Fingerabdruck verwenden"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zu hell"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Versuche, den Finger anders aufzulegen"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerabdruck wurde authentifiziert"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Keine Fingerabdrücke erfasst."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dieses Gerät hat keinen Fingerabdrucksensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Der Sensor ist vorübergehend deaktiviert."</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Fingerabdruck verwenden"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Fingerabdruck oder Displaysperre verwenden"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index fce9d98005c8..0dec36bae4e2 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Δοκιμάστε άλλο δακτυλικό αποτύπωμα"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Υπερβολικά έντονος φωτισμός"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Δοκιμάστε να το προσαρμόσετε"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Η ταυτότητα του δακτυλικού αποτυπώματος ελέγχθηκε"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Δεν έχουν καταχωριστεί δακτυλικά αποτυπώματα."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Αυτή η συσκευή δεν διαθέτει αισθητήρα δακτυλικού αποτυπώματος."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Ο αισθητήρας απενεργοποιήθηκε προσωρινά."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Ο αισθητήρας απαιτεί βαθμονόμηση"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Δάχτυλο <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Χρήση δακτυλικού αποτυπώματος"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Χρήση δακτυλικού αποτυπώματος ή κλειδώματος οθόνης"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 805f344ed20b..dc7528bc3b85 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 86ddb1f7cb72..db3d9f5c1e3a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index da1c49a93603..c2ca3140f5a0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index eeedf2109517..994946fac6de 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Try another fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Too bright"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Try adjusting"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Change the position of your finger slightly each time"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingerprint authenticated"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporarily disabled."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor needs calibration"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Use fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Use fingerprint or screen lock"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5a2d3f340cd1..2fe89de65078 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‏‏‎‎‎‎‎‏‎Try another fingerprint‎‏‎‎‏‎"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‎Too bright‎‏‎‎‏‎"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‏‎‎‎Try adjusting‎‏‎‎‏‎"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎Change the position of your finger slightly each time‎‏‎‎‏‎"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎Fingerprint authenticated‎‏‎‎‏‎"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎No fingerprints enrolled.‎‏‎‎‏‎"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎This device does not have a fingerprint sensor.‎‏‎‎‏‎"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎Sensor temporarily disabled.‎‏‎‎‏‎"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎Sensor needs calibration‎‏‎‎‏‎"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‎Finger ‎‏‎‎‏‏‎<xliff:g id="FINGERID">%d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‎‎Use fingerprint‎‏‎‎‏‎"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎Use fingerprint or screen lock‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d3614f1b6df9..e20574c68e24 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella dactilar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prueba ajustarla"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia un poco la posición del dedo cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se autenticó la huella dactilar"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se registraron huellas digitales."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas dactilares."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Se inhabilitó temporalmente el sensor."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Se debe calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar bloqueo de huella dactilar o pantalla"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 72571596b524..03d852991509 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prueba con otra huella digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prueba a mover el dedo"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Se ha autenticado la huella digital"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No se ha registrado ninguna huella digital."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo no tiene sensor de huellas digitales."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"El sensor está inhabilitado en estos momentos."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Hace falta calibrar el sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar huella digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar huella digital o bloqueo de pantalla"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1ae8730a90e4..efac8bcb9d56 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Võimaldab rakendusel laiendada või ahendada olekuriba."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"Kuva märguanded lukustatud seadmes täisekraantegevustena"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Lubab rakendusel märguandeid lukustatud seadmes täisekraantegevustena kuvada"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"otseteede installimine"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Otseteede installimine"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Lubab rakendusel lisada avakuva otseteid ilma kasutaja sekkumiseta."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"otseteede desinstallimine"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Lubab rakendusel eemaldada avakuva otseteid ilma kasutaja sekkumiseta."</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proovige teist sõrmejälge"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liiga ere"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Proovige kohandada"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sõrmejälg autenditi"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Andurit on vaja kalibreerida"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sõrmejälje kasutamine"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sõrmejälje või ekraaniluku kasutamine"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index de6e5e769e56..708d7d674d63 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Erabili beste hatz-marka bat"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Argi gehiegi dago"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Saiatu doituta"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentifikatu da hatz-marka"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ez da erregistratu hatz-markarik."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Gailu honek ez du hatz-marken sentsorerik."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sentsorea aldi baterako desgaitu da."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sentsorea kalibratu egin behar da"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. hatza"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Erabili hatz-marka"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Erabili hatz-marka edo pantailaren blokeoa"</string>
@@ -1053,8 +1056,8 @@
<string name="last_month" msgid="1528906781083518683">"Azken hilabetea"</string>
<string name="older" msgid="1645159827884647400">"Zaharragoa"</string>
<string name="preposition_for_date" msgid="2780767868832729599">"<xliff:g id="DATE">%s</xliff:g>"</string>
- <string name="preposition_for_time" msgid="4336835286453822053">"ordua: <xliff:g id="TIME">%s</xliff:g>"</string>
- <string name="preposition_for_year" msgid="3149809685340130039">"urtea: <xliff:g id="YEAR">%s</xliff:g>"</string>
+ <string name="preposition_for_time" msgid="4336835286453822053">"<xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="preposition_for_year" msgid="3149809685340130039">"<xliff:g id="YEAR">%s</xliff:g>"</string>
<string name="day" msgid="8394717255950176156">"egun"</string>
<string name="days" msgid="4570879797423034973">"egun"</string>
<string name="hour" msgid="7796325297097314653">"ordu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cc2223cacbb6..0667fed4f013 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"اثر انگشت دیگری را امتحان کنید"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"خیلی روشن است"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"اثر انگشت را تنظیم کنید"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"اثر انگشت اصالت‌سنجی شد"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"اثر انگشتی ثبت نشده است."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"این دستگاه حسگر اثر انگشت ندارد."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"حسگر به‌طور موقت غیرفعال است."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"حسگر به واسنجی نیاز دارد"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگشت <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"استفاده از اثر انگشت"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"استفاده از اثر انگشت یا قفل صفحه"</string>
@@ -906,12 +909,12 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"لطفاً به راهنمای کاربر مراجعه کرده یا با مرکز پشتیبانی از مشتریان تماس بگیرید."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"سیم کارت قفل شد."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"بازگشایی قفل سیم کارت…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"‏الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎‌اید. \n\nپس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"گذرواژهٔ خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کرده‌اید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"‏پین را<xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کرده‎اید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که برای بازگشایی قفل رایانهٔ لوحی خود به Google وارد شوید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"‏<xliff:g id="NUMBER_0">%1$d</xliff:g> بار الگوی بازگشایی‌تان را اشتباه کشیده‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید،‌ از شما خواسته می‌شود با اطلاعات ورود به سیستم Google خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"‏الگوی قفل‌گشایی را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر از شما خواسته می‎شود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید.\n\n پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎‌اید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎‌شود که برای بازگشایی قفل رایانهٔ لوحی‌تان به Google وارد شوید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید،‌ از شما خواسته می‌شود با اطلاعات ورود به سیستم Google خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، از شما خواسته می‌‎شود که برای بازگشایی قفل گوشی به برنامه Google وارد شوید.\n\n پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل رایانهٔ لوحی کرده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، رایانهٔ لوحی به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"‏<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشته‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، دستگاه Android TV شما به تنظیمات پیش‌فرض کارخانه بازنشانی خواهد شد و همه داده‌های کاربر ازدست خواهد رفت."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. پس از<xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
@@ -1669,16 +1672,16 @@
<string name="kg_login_checking_password" msgid="4676010303243317253">"درحال بررسی حساب..."</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. \n\nلطفاً پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کرده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، رایانهٔ لوحی به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"‏<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشته‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، دستگاه Android TV شما به تنظیمات پیش‌فرض کارخانه بازنشانی خواهد شد و همه داده‌های کاربر ازدست خواهد رفت."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"شما به اشتباه <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، تلفن به پیش‌فرض کارخانه بازنشانی می‌شود و تمام داده‌های کاربر از دست خواهد رفت."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل رایانه لوحی کرده‌اید. رایانه لوحی اکنون به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"‏<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل Android TV خود داشته‌اید. اکنون دستگاه Android TV شما به تنظیمات پیش‌فرض کارخانه بازنشانی می‌شود."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"شما به اشتباه <xliff:g id="NUMBER">%d</xliff:g> بار اقدام به باز کردن قفل تلفن کرده‌اید. این تلفن اکنون به پیش‌فرض کارخانه بازنشانی می‌شود."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"‏<xliff:g id="NUMBER_0">%1$d</xliff:g> بار الگوی بازگشایی‌تان را اشتباه کشیده‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته می‌شود بااستفاده از حساب ایمیل خود، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"‏شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌‎اید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎‌شود که بااستفاده از یک حساب ایمیل قفل رایانه لوحی‌تان را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. اگر <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر داشته باشید، از شما خواسته می‌شود بااستفاده از حساب ایمیلتان، قفل دستگاه Android TV را باز کنید.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دیگر دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌‎شود که بااستفاده از یک حساب ایمیل قفل تلفنتان را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"حذف"</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"میزان صدا را به بالاتر از حد توصیه شده افزایش می‌دهید؟\n\nگوش دادن به صداهای بلند برای مدت طولانی می‌تواند به شنوایی‌تان آسیب وارد کند."</string>
@@ -1862,7 +1865,7 @@
<string name="managed_profile_label_badge_2" msgid="5673187309555352550">"کار دوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="6882151970556391957">"کار سوم <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"درخواست کد پین قبل از برداشتن پین"</string>
- <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی باز کردن قفل قبل از برداشتن سنجاق"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبل‌از برداشتن سنجاق"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string>
<string name="package_installed_device_owner" msgid="7035926868974878525">"توسط سرپرست سیستم نصب شد"</string>
<string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 1b28ca1e5f05..2ae93b823536 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Kokeile toista sormenjälkeä"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Liian kirkas"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Kokeile muuttaa asentoa"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sormenjälki tunnistettu"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Sormenjälkiä ei ole otettu käyttöön."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Laitteessa ei ole sormenjälkitunnistinta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tunnistin poistettu väliaikaisesti käytöstä."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Tunnistin on kalibroitava"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Sormi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Käytä sormenjälkeä"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Käytä sormenjälkeä tai näytön lukitusta"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index fa3737843761..143f3be59622 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte digitale"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop lumineux"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Essayez de l\'ajuster"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Cet appareil ne possède pas de capteur d\'empreintes digitales."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Le capteur a été désactivé temporairement."</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser l\'empreinte digitale ou le verrouillage de l\'écran"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 0ee3c889fdb2..829c07cb97c7 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Essayez une autre empreinte"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Trop de lumière"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Essayez de repositionner le doigt"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Empreinte digitale authentifiée"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Aucune empreinte digitale enregistrée."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Aucun lecteur d\'empreinte digitale n\'est installé sur cet appareil."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Capteur temporairement désactivé."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Vous devez calibrer le capteur"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Doigt <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utiliser l\'empreinte digitale"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utiliser votre empreinte digitale ou le verrouillage de l\'écran"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 5e10fdb8eb45..22a25c9ccc92 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Proba con outra impresión dixital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Hai demasiada luz"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Proba a axustar a impresión dixital"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autenticouse a impresión dixital"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Non se rexistraron impresións dixitais."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo non ten sensor de impresión dixital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Desactivouse o sensor temporalmente."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"É necesario calibrar o sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar impresión dixital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar impresión dixital ou credencial do dispositivo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 4157e1fd32eb..702e169f995d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"અન્ય ફિંગરપ્રિન્ટ અજમાવી જુઓ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"અતિશય પ્રકાશિત"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ગોઠવણી કરી જુઓ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ફિંગરપ્રિન્ટ પ્રમાણિત કરી"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"કોઈ ફિંગરપ્રિન્ટની નોંધણી કરવામાં આવી નથી."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"આ ડિવાઇસમાં કોઈ ફિંગરપ્રિન્ટ સેન્સર નથી."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"સેન્સર હંગામી રૂપે બંધ કર્યું છે."</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"આંગળી <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ફિંગરપ્રિન્ટ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
@@ -1458,10 +1462,8 @@
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ઍપ્લિકેશનને પૅકેજો કાઢી નાખવાની વિનંતી કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવા માટે પૂછો"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ઍપ્લિકેશનને તે ઍપ્લિકેશન માટે બૅટરી ઓપ્ટિમાઇઝેશન્સને અવગણવાની પરવાનગી આપવા માટે પૂછવાની મંજૂરી આપે છે."</string>
- <!-- no translation found for permlab_queryAllPackages (2928450604653281650) -->
- <skip />
- <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) -->
- <skip />
+ <string name="permlab_queryAllPackages" msgid="2928450604653281650">"બધા પૅકેજ જુઓ"</string>
+ <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"કોઈ ઍપને ઇન્સ્ટૉલ કરેલા બધા પૅકેજ જોવાની મંજૂરી આપે છે."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ઝૂમ નિયંત્રણ માટે બેવાર ટૅપ કરો"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"વિજેટ ઉમેરી શકાયું નથી."</string>
<string name="ime_action_go" msgid="5536744546326495436">"જાઓ"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8fe4ebfee33e..8c668dcf1de8 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"किसी दूसरे फ़िंगरप्रिंट से कोशिश करें"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"बहुत रोशनी है"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"सेंसर पर सही तरीके से उंगली लगाने की कोशिश करें"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फ़िंगरप्रिंट की पुष्टि हो गई"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"सेंसर को कैलिब्रेट करने की ज़रूरत है"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"फ़िंगरप्रिंट <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फ़िंगरप्रिंट इस्तेमाल करें"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फ़िंगरप्रिंट या स्क्रीन लॉक का क्रेडेंशियल इस्तेमाल करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 630ba2bece23..eb90708a9948 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Isprobajte drugi otisak prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvijetlo"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pokušajte ga prilagoditi"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Svaki put lagano promijenite položaj prsta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Autentificirano otiskom prsta"</string>
@@ -604,6 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nije registriran nijedan otisak prsta."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ovaj uređaj nema senzor otiska prsta."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je privremeno onemogućen."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Potrebno je kalibrirati senzor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Upotreba otiska prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Upotreba otiska prsta ili zaključavanja zaslona"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index f945d395a6e5..77db9e600f7c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Próbálkozzon másik ujjlenyomattal"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Túl világos"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Próbálja beállítani"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Ujjlenyomat hitelesítve"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nincsenek regisztrált ujjlenyomatok."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ez az eszköz nem rendelkezik ujjlenyomat-érzékelővel."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Az érzékelő átmenetileg le van tiltva."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Az érzékelő kalibrálást igényel"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. ujj"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Ujjlenyomat használata"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"A folytatás ujjlenyomattal vagy képernyőzárral lehetséges"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index d3057ca30809..0a18bfa80232 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Փորձեք մեկ այլ մատնահետք"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Շատ լուսավոր է"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Փորձեք փոխել մատի դիրքը"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Ամեն անգամ թեթևակի փոխեք մատի դիրքը"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Մատնահետքը նույնականացվեց"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Գրանցված մատնահետք չկա:"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Այս սարքը չունի մատնահետքերի սկաներ։"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Տվիչը ժամանակավորապես անջատված է:"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Սկաներն անհրաժեշտ է չափաբերել"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Մատնահետք <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Օգտագործել մատնահետք"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Օգտագործել մատնահետք կամ էկրանի կողպում"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index abe36081900e..58cfdd78da49 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Coba sidik jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Coba sesuaikan"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Sidik jari diautentikasi"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tidak ada sidik jari yang terdaftar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Perangkat ini tidak memiliki sensor sidik jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor dinonaktifkan untuk sementara."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor memerlukan kalibrasi"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan sidik jari"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan sidik jari atau kunci layar"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 6be07b0056b0..210be916cd09 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prófaðu annað fingrafar"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Of bjart"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prófaðu að breyta stöðu fingursins"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingrafar staðfest"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Engin fingraför hafa verið skráð."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Þetta tæki er ekki með fingrafaralesara."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Slökkt tímabundið á skynjara."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kvarða þarf skynjarann"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Fingur <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Nota fingrafar"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Nota fingrafar eða skjálás"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d4f2fdb08395..7d08000bc97e 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prova con un\'altra impronta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Troppa luce"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prova a regolare"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Cambia leggermente la posizione del dito ogni volta"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impronta autenticata"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nessuna impronta digitale registrata."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Questo dispositivo non dispone di sensore di impronte."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensore temporaneamente disattivato."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"È necessario calibrare il sensore"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dito <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usa l\'impronta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usa l\'impronta o il blocco schermo"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7c9d97ecdd76..8b3aecea68c0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"יש להשתמש בטביעת אצבע אחרת"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"בהיר מדי"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"יש לנסות ולשנות את תנוחת האצבע"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"טביעת האצבע אומתה"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"לא נסרקו טביעות אצבע."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"במכשיר הזה אין חיישן טביעות אצבע."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"החיישן מושבת באופן זמני."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"צריך לכייל את החיישן"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"אצבע <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"שימוש בטביעת אצבע"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"שימוש בטביעת אצבע או בנעילת מסך"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 39681875a345..7b62919560ef 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"別の指紋をお試しください"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"明るすぎます"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"調整してみてください"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋認証を完了しました"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"指紋が登録されていません。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"このデバイスには指紋認証センサーがありません。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"センサーが一時的に無効になっています。"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"センサーの調整が必要です"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"指紋 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"指紋の使用"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"指紋または画面ロックの使用"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index e941b5e48806..8d9b99c4b5de 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ცადეთ სხვა თითის ანაბეჭდი"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ზედმეტად ნათელია"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ცადეთ დარეგულირება"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"თითის ანაბეჭდი ავტორიზებულია"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"თითის ანაბეჭდები რეგისტრირებული არ არის."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ამ მოწყობილობას არ აქვს თითის ანაბეჭდის სენსორი."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"სენსორი დროებით გათიშულია."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"სენსორს კალიბრაცია სჭირდება"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"თითი <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"გამოიყენეთ თითის ანაბეჭდი ან ეკრანის დაბლოკვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 1324d2d4ce60..80bddc7b6925 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Басқа саусақ ізін байқап көріңіз."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Тым жарық."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Дұрыстап қойып көріңіз."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Саусақ ізі аутентификацияланды"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Саусақ іздері тіркелмеген."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бұл құрылғыда саусақ ізін оқу сканері жоқ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик уақытша өшірулі."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Датчикті калибрлеу қажет."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-саусақ"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Саусақ ізін пайдалану"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Саусақ ізін немесе экран құлпын пайдалану"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index df0b08299bb1..aaa188b2fe62 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"សាកល្បងប្រើ​ស្នាមម្រាមដៃផ្សេងទៀត"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ភ្លឺពេក"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"សាកល្បង​កែតម្រូវ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"បាន​ផ្ទៀង​ផ្ទាត់​ស្នាម​ម្រាមដៃ"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"មិន​មាន​ការ​ចុះឈ្មោះស្នាម​ម្រាមដៃទេ។"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ឧបករណ៍នេះ​មិនមាន​ឧបករណ៍ចាប់​ស្នាមម្រាមដៃទេ។"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"បានបិទ​ឧបករណ៍​ចាប់សញ្ញាជា​បណ្តោះអាសន្ន។"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ឧបករណ៍​ចាប់សញ្ញាត្រូវការកែសម្រួល"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ម្រាមដៃ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ប្រើស្នាមម្រាមដៃ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ប្រើស្នាមម្រាមដៃ ឬ​ការចាក់សោអេក្រង់"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index a8e5b6403a4d..fc7fa3bb05b6 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ಮತ್ತೊಂದು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಪ್ರಯತ್ನಿಸಿ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ತುಂಬಾ ಪ್ರಕಾಶಮಾನವಾಗಿದೆ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಅನ್ನು ಪ್ರಮಾಣೀಕರಣ ಮಾಡಲಾಗಿದೆ"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ಯಾವುದೇ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್‌ ಅನ್ನು ನೋಂದಣಿ ಮಾಡಿಲ್ಲ."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ಈ ಸಾಧನವು ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್‌‌ ಅನ್ನು ಹೊಂದಿಲ್ಲ."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ಸೆನ್ಸಾರ್ ಅನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ಸೆನ್ಸರ್‌ಗೆ ಕ್ಯಾಲಿಬ್ರೇಶನ್‌ನ ಅಗತ್ಯವಿದೆ"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ಫಿಂಗರ್ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಬಳಸಿ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ಫಿಂಗರ್‌ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index cf9ade76183c..14b8514826c9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"다른 지문으로 시도"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"너무 밝음"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"조정 시도"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"지문이 인증됨"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"등록된 지문이 없습니다."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"기기에 지문 센서가 없습니다."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"센서가 일시적으로 사용 중지되었습니다."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"센서 보정 필요"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"지문 사용"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"지문 또는 화면 잠금 사용"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 5479f119c2ba..ccfdef8a56ed 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Башка манжа изин байкап көрүңүз"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Өтө жарык"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Тууралап көрүңүз"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Манжа изи текшерилди"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бир да манжа изи катталган эмес."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Бул түзмөктө манжа изинин сенсору жок."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сенсор убактылуу өчүрүлгөн."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сенсорду тууралоо керек"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>-манжа"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Манжа изин колдонуу"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Манжа изин же экрандын кулпусун колдонуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index ee2f058393df..e89dba7595e0 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ລອງໃຊ້ລາຍນິ້ວມືອື່ນ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ແຈ້ງເກີນໄປ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ກະລຸນາລອງປັບແກ້"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"ປ່ຽນຕຳແໜ່ງຂອງນິ້ວມືຂອງທ່ານເລັກນ້ອຍໃນແຕ່ລະເທື່ອ"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ພິສູດຢືນຢັນລາຍນິ້ວມືແລ້ວ"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ບໍ່ມີການລົງທະບຽນລາຍນິ້ວມື."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ອຸປະກອນນີ້ບໍ່ມີເຊັນເຊີລາຍນິ້ວມື."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ປິດການເຮັດວຽກຂອງເຊັນເຊີໄວ້ຊົ່ວຄາວແລ້ວ."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ຕ້ອງປັບທຽບມາດຕະຖານເຊັນເຊີ"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ນີ້ວ​ມື <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ໃຊ້ລາຍນິ້ວມື"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 8ebb09ede62c..ee9e61d6fbb9 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Pabandykite kitą kontrolinį kodą"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Per šviesu"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Pabandykite koreguoti"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Piršto antspaudas autentifikuotas"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neužregistruota jokių kontrolinių kodų."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šiame įrenginyje nėra kontrolinio kodo jutiklio."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Jutiklis laikinai išjungtas."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Reikia sukalibruoti jutiklį"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> pirštas"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Naudoti kontrolinį kodą"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Naudoti kontrolinį kodą arba ekrano užraktą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 9b86c4d7fc7f..1a90a81e2992 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -588,6 +588,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Izmēģiniet citu pirksta nospiedumu"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Pārāk spilgts"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Mēģiniet mainīt pozīciju"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pirksta nospiedums tika autentificēts."</string>
@@ -604,6 +606,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nav reģistrēts neviens pirksta nospiedums."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Šajā ierīcē nav pirksta nospieduma sensora."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensors ir īslaicīgi atspējots."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Nepieciešama sensora kalibrēšana."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. pirksts"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Pirksta nospieduma izmantošana"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Pirksta nospieduma vai ekrāna bloķēšanas metodes izmantošana"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index d0e11f1e8039..e0283074419f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте со друг отпечаток"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Премногу светло"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Пробајте да го приспособите прстот"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечатокот е проверен"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Не се запишани отпечатоци."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Уредов нема сензор за отпечатоци."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензорот е привремено оневозможен."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сензорот треба да се калибрира"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користи отпечаток"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користи отпечаток или заклучување екран"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 22fac7ed594f..1b2e5950427a 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"മറ്റൊരു ഫിംഗർപ്രിന്റ് ഉപയോഗിച്ച് നോക്കുക"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"തെളിച്ചം വളരെയധികമാണ്"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"അൽപ്പം നീക്കി നോക്കൂ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ഫിംഗർപ്രിന്റ് പരിശോധിച്ചുറപ്പിച്ചു"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"വിരലടയാളങ്ങൾ എൻറോൾ ചെയ്തിട്ടില്ല."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ഈ ഉപകരണത്തിൽ ഫിംഗർപ്രിന്റ് സെൻസറില്ല."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"സെൻസർ താൽക്കാലികമായി പ്രവർത്തനരഹിതമാക്കി."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"സെൻസറിന് കാലിബ്രേഷൻ ആവശ്യമാണ്"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ഫിംഗർ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ഫിംഗർപ്രിന്റ് അല്ലെങ്കിൽ സ്‌ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1060f64fdb1c..d21ce23b4ac5 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Өөр хурууны хээ туршина уу"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Хэт гэрэлтэй байна"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Тохируулж үзнэ үү"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Хурууны хээг нотолсон"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Бүртгүүлсэн хурууны хээ алга."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Энэ төхөөрөмжид хурууны хээ мэдрэгч алга."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Мэдрэгчийг түр хугацаанд идэвхгүй болгосон."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Мэдрэгчид тохируулга шаардлагатай"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Хурууны хээ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Хурууны хээ ашиглах"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Хурууны хээ эсвэл дэлгэцийн түгжээ ашиглах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index bf5f8e7a827e..f1b21c04246f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"स्टेटस बार विस्तृत करण्यासाठी किंवा संक्षिप्त करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लॉक केलेल्या डिव्हाइसवर फुल स्क्रीन अ‍ॅक्टिव्हिटी म्हणून सूचना प्रदर्शित करणे"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"लॉक केलेल्या डिव्हाइसवर फुल स्क्रीन अ‍ॅक्टिव्हिटी म्हणून सूचना प्रदर्शित करण्यासाठी ॲपला अनुमती द्या"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"शॉर्टकट स्‍थापित करा"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"शॉर्टकट इंस्टॉल करा"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"अनुप्रयोगाला वापरकर्ता हस्‍तक्षेपाशिवाय मुख्‍यस्‍क्रीन शॉर्टकट जोडण्‍याची अनुमती देते."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"शॉर्टकट विस्‍थापित करा"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"अनुप्रयोगाला वापरकर्ता हस्‍तक्षेपाशिवाय मुख्‍यस्‍क्रीन शॉर्टकट काढण्‍याची अनुमती देते."</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"दुसरी फिंगरप्रिंट वापरून पाहा"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"खूप प्रखर"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"अ‍ॅडजस्ट करण्याचा प्रयत्न करा"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिंट ऑथेंटिकेट केली आहे"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोणत्याही फिंगरप्रिंटची नोंद झाली नाही"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"या डिव्हाइसमध्ये फिंगरप्रिंट सेन्सर नाही."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेन्सर तात्पुरता बंद केला आहे."</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g> बोट"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फिंगरप्रिंट वापरा"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फिंगरप्रिंट किंवा स्क्रीन लॉक वापरा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index ccc0828daafb..bcc502a4dac0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Cuba cap jari lain"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Terlalu terang"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Cuba selaraskan"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Cap jari disahkan"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Tiada cap jari didaftarkan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Peranti ini tiada penderia cap jari."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Penderia dilumpuhkan sementara."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Penderia memerlukan penentukuran"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Jari <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gunakan cap jari"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gunakan cap jari atau kunci skrin"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 7797e0875c2e..97db71550f54 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"အခြားလက်ဗွေဖြင့် စမ်းကြည့်ပါ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"အလွန် လင်းသည်"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ပြင်ဆင်ကြည့်ပါ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"လက်ဗွေကို အထောက်အထား စိစစ်ပြီးပါပြီ"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"မည်သည့် လက်ဗွေကိုမျှ ထည့်သွင်းမထားပါ။"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ဤစက်တွင် လက်ဗွေအာရုံခံကိရိယာ မရှိပါ။"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"အာရုံခံကိရိယာကို ယာယီပိတ်ထားသည်။"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"အာရုံခံကိရိယာက စံကိုက်ချိန်ညှိခြင်း လိုအပ်သည်"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"လက်ချောင်း <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"လက်ဗွေ သုံးခြင်း"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ချခြင်းကို သုံးခြင်း"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 395dc1da2f03..bb29d8e84094 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Prøv et annet fingeravtrykk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"For lyst"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Prøv å justere"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrykket er godkjent"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ingen fingeravtrykk er registrert."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Denne enheten har ikke fingeravtrykkssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensoren er midlertidig slått av."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensoren må kalibreres"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Bruk fingeravtrykk"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Bruk fingeravtrykk eller skjermlås"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 130adcdcf6c9..c712fbd5007c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -349,7 +349,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"एपलाई स्थिति पट्टि विस्तार वा संकुचन गर्न अनुमति दिन्छ।"</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाइयोस्"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"यो अनुमति दिइएमा एपले लक गरिएको डिभाइसमा स्क्रिनभरि देखिने सूचनाहरू देखाउन सक्छ"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट स्थापना गर्नुहोस्"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"सर्टकट इन्स्टल गर्ने"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिन्छ।"</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"सर्टकटहरूको स्थापन रद्द गर्नुहोस्"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा हटाउनको लागि अनुमति दिन्छ।"</string>
@@ -438,9 +438,9 @@
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"अधिक स्थान प्रदायक आदेशहरू पहुँच गर्नुहोस्"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"एपलाई अतिरिक्त स्थान प्रदायक आदेशहरू पहुँच गर्न अनुमति दिन्छ। यो एपलाई GPS वा अन्य स्थान स्रोतहरूको संचालन साथै हस्तक्षेप गर्न अनुमति दिन सक्छ।"</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"अग्रभूमिमा मात्र सटीक स्थानमाथि पहुँच राख्नुहोस्"</string>
- <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"यो एप चलाएका बेला यसले लोकेसनमा आधारित सेवाहरूबाट तपाईंको स्थानको सटीक जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसनमा आधारित सेवाहरू सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ। यसले ब्याट्रीको उपयोग बढाउन सक्छ।"</string>
+ <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"यो एप चलाएका बेला यसले लोकेसन सर्भिसबाट तपाईंको स्थानको सटीक जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसन सर्भिस सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ। यसले ब्याट्रीको उपयोग बढाउन सक्छ।"</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"अग्रभागमा मात्र अनुमानित स्थानमाथि पहुँच राख्नुहोस्"</string>
- <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"यो एप चलाएका बेला यसले लोकेसनमा आधारित सेवाहरूबाट तपाईंको स्थानको अनुमानित जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसनमा आधारित सेवाहरू सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ।"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"यो एप चलाएका बेला यसले लोकेसन सर्भिसबाट तपाईंको स्थानको अनुमानित जानकारी प्राप्त गर्न सक्छ। तपाईंको डिभाइसमा लोकेसन सर्भिस सक्रिय गरिएको छ भने मात्र यो एपले स्थानको जानकारी प्राप्त गर्न सक्छ।"</string>
<string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"पृष्ठभूमिमा स्थानसम्बन्धी पहुँच"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"यो एपले जुनसुकै बेला (एप नचलाएका बेलामा पनि) स्थानमाथि पहुँच राख्न सक्छ।"</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"तपाईँका अडियो सेटिङहरू परिवर्तन गर्नुहोस्"</string>
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"अर्को फिंगरप्रिन्ट प्रयोग गरी हेर्नुहोस्"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ज्यादै उज्यालो छ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"सेन्सरमा सही तरिकाले औँला राखेर हेर्नुहोस्"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कुनै पनि फिंगरप्रिन्ट दर्ता गरिएको छैन।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"यो डिभाइसमा कुनै पनि फिंगरप्रिन्ट सेन्सर छैन।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"केही समयका लागि सेन्सर असक्षम पारियो।"</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"औंला <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"फिंगरप्रिन्ट वा स्क्रिन लक प्रयोग गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 9449ac1cfb91..cc75bd61c458 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Probeer een andere vingerafdruk"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Te veel licht"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Verplaats je vinger"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Verander de positie van je vinger steeds een beetje"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Vingerafdruk geverifieerd"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Geen vingerafdrukken geregistreerd."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dit apparaat heeft geen vingerafdruksensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor staat tijdelijk uit."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensor moet worden gekalibreerd"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Vingerafdruk gebruiken"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Vingerafdruk of schermvergrendeling gebruiken"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index b609827b9918..f2fbbd02116c 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ଅନ୍ୟ ଏକ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ବହୁତ ଉଜ୍ଜ୍ୱଳ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ଆଡଜଷ୍ଟ କରି ଦେଖନ୍ତୁ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ଟିପଚିହ୍ନ ପ୍ରମାଣିତ ହେଲା"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"କୌଣସି ଆଙ୍ଗୁଠି ଚିହ୍ନ ପଞ୍ଜୀକୃତ ହୋଇନାହିଁ।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ଏହି ଡିଭାଇସ୍‌ରେ ଟିପଚିହ୍ନ ସେନ୍‍ସର୍ ନାହିଁ।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ସେନ୍ସରକୁ ଅସ୍ଥାୟୀ ଭାବେ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"ଆଙ୍ଗୁଠି <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ଟିପଚିହ୍ନ ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 2efcc76bae52..180468025a72 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ਕੋਈ ਹੋਰ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਚਮਕ"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ਵਿਵਸਥਿਤ ਕਰਕੇ ਦੇਖੋ"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਮਾਣਿਤ ਹੋਇਆ"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ਕੋਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਦਰਜ ਨਹੀਂ ਕੀਤੇ ਗਏ।"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ਇਸ ਡੀਵਾਈਸ ਵਿੱਚ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨਹੀਂ ਹੈ।"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ਸੈਂਸਰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"ਉਂਗਲ <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 49890fc64d27..06c7779e7746 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -591,6 +591,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Użyj odcisku innego palca"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Zbyt jasno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Popraw"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Za każdym razem lekko zmieniaj ułożenie palca"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Uwierzytelniono odciskiem palca"</string>
@@ -607,6 +608,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nie zarejestrowano odcisków palców."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"To urządzenie nie jest wyposażone w czytnik linii papilarnych."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Czujnik jest tymczasowo wyłączony."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Czujnik wymaga kalibracji"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Używaj odcisku palca"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Używaj odcisku palca lub blokady ekranu"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f4c0cdbcd2aa..8729940ad51b 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ajuste a posição do dedo"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor precisa ser calibrado"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f1c847647ae6..543abc30fac3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Experimente outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Está demasiado claro"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Experimente ajustar"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Altere a posição do seu dedo ligeiramente de cada vez"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"A impressão digital foi autenticada."</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem sensor de impressões digitais."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor temporariamente desativado."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor necessita de calibração"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Utilizar a impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Utilizar o bloqueio de ecrã ou a impressão digital"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f4c0cdbcd2aa..8729940ad51b 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Use outra impressão digital"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Claro demais"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ajuste a posição do dedo"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Mude a posição do dedo ligeiramente a cada momento"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Impressão digital autenticada"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nenhuma impressão digital registrada."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Este dispositivo não tem um sensor de impressão digital."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor desativado temporariamente."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"O sensor precisa ser calibrado"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Dedo <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Usar impressão digital"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Usar impressão digital ou bloqueio de tela"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c50f2e3a99c0..8e005e60a55e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -352,7 +352,7 @@
<string name="permdesc_expandStatusBar" msgid="7180756900448498536">"Permite aplicației să extindă sau să restrângă bara de stare."</string>
<string name="permlab_fullScreenIntent" msgid="4310888199502509104">"să afișeze notificări ca activități pe ecran complet pe un dispozitiv blocat"</string>
<string name="permdesc_fullScreenIntent" msgid="1100721419406643997">"Permite aplicației să afișeze notificări ca activități pe ecran complet pe un dispozitiv blocat"</string>
- <string name="permlab_install_shortcut" msgid="7451554307502256221">"instalează comenzi rapide"</string>
+ <string name="permlab_install_shortcut" msgid="7451554307502256221">"Instalarea de comenzi rapide"</string>
<string name="permdesc_install_shortcut" msgid="4476328467240212503">"Permite unei aplicații să adauge comenzi rapide pe ecranul de pornire, fără intervenția utilizatorului."</string>
<string name="permlab_uninstall_shortcut" msgid="295263654781900390">"dezinstalează comenzi rapide"</string>
<string name="permdesc_uninstall_shortcut" msgid="1924735350988629188">"Permite aplicației să elimine comenzi rapide de pe ecranul de pornire, fără intervenția utilizatorului."</string>
@@ -588,6 +588,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Încercați altă amprentă"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Prea luminos"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Încercați să ajustați"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Amprentă autentificată"</string>
@@ -604,6 +606,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nu au fost înregistrate amprente."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Dispozitivul nu are senzor de amprentă."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzorul necesită calibrare"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Folosiți amprenta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Folosiți amprenta sau blocarea ecranului"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index dde5ebc88d59..2d177cc3ded2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Попробуйте сохранить отпечаток другого пальца."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Слишком светло."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Попробуйте изменить положение пальца."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отпечаток пальца проверен"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Нет отсканированных отпечатков пальцев"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На этом устройстве нет сканера отпечатков пальцев."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сканер отпечатков пальцев временно отключен."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Требуется калибровка датчика."</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Отпечаток <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Использовать отпечаток пальца"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Использовать отпечаток пальца или блокировку экрана"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 13df5e2db962..e6d795618995 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"තවත් ඇඟිලි සලකුණක් උත්සාහ කරන්න"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"දීප්තිය වැඩියි"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"සීරුමාරු කිරීම උත්සාහ කරන්න"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ඇඟිලි සලකුණ සත්‍යාපනය කරන ලදී"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ඇඟිලි සලකුණු ඇතුළත් කර නොමැත."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"මෙම උපාංගයේ ඇඟිලි සලකුණු සංවේදකයක් නොමැත."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"සංවේදකය තාවකාලිකව අබල කර ඇත."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"සංවේදකයට ක්‍රමාංකනය අවශ්‍යයි"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"ඇඟිලි <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 4f8329a5e985..18dcef3dbb59 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Vyskúšajte iný odtlačok prsta"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Príliš jasno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Vyskúšajte upraviť"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Odtlačok prsta bol overený"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Neregistrovali ste žiadne odtlačky prstov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Toto zariadenie nemá senzor odtlačkov prstov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzor je dočasne vypnutý."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Senzor vyžaduje kalibráciu"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst: <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Použiť odtlačok prsta"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Použiť odtlačok prsta alebo zámku obrazovky"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index fb6fc9ae4b16..0f13454ebdad 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -591,6 +591,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Poskusite z drugim prstnim odtisom."</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Presvetlo je."</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Poskusite popraviti položaj prsta."</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Pristnost prstnega odtisa je preverjena"</string>
@@ -607,6 +609,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Tipalo je treba umeriti"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Uporaba prstnega odtisa"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Uporaba prstnega odtisa ali odklepanja s poverilnico"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 646cc854a631..2d45dd32b386 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Provo një gjurmë gishti tjetër"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Me shumë ndriçim"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Provo ta rregullosh"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Gjurma e gishtit u vërtetua"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Nuk ka asnjë gjurmë gishti të regjistruar."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kjo pajisje nuk ka sensor të gjurmës së gishtit."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensori është çaktivizuar përkohësisht."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensori ka nevojë për kalibrim"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Gishti <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Përdor gjurmën e gishtit"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Përdor gjurmën e gishtit ose kyçjen e ekranit"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 98ddb39e1680..6b96632479f6 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -588,6 +588,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Пробајте са другим отиском прста"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Превише је светло"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Пробајте да прилагодите"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Сваки пут лагано промените положај прста"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Отисак прста је потврђен"</string>
@@ -604,6 +605,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Није регистрован ниједан отисак прста."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Овај уређај нема сензор за отисак прста."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Сензор је привремено онемогућен."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Сензор треба да се калибрише"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Користите отисак прста"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Користите отисак прста или закључавање екрана"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index f155f3cd0c36..58fcd9da730e 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Testa ett annat fingeravtryck"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Det är för ljust"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Testa att justera fingeravtrycket"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Fingeravtrycket har autentiserats"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Inga fingeravtryck har registrerats."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Enheten har ingen fingeravtryckssensor."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensorn måste kalibreras"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 8ca0ac0f1aa1..8b34ba2a3500 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Jaribu alama nyingine ya kidole"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Inang\'aa mno"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Jaribu kurekebisha"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Badilisha mkao wa kidole chako kiasi kila wakati"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Imethibitisha alama ya kidole"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hakuna alama za vidole zilizojumuishwa."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Kifaa hiki hakina kitambua alama ya kidole."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Kitambuzi kimezimwa kwa muda."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kitambuzi kinahitaji kurekebishwa"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Kidole cha <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Tumia alama ya kidole"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Tumia alama ya kidole au mbinu ya kufunga skrini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 4a50960dd1e9..adb8c4764312 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"வேறு கைரேகையை முயலவும்"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"அதிக வெளிச்சமாக உள்ளது"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"விரலைச் சரியாக வைக்கவும்"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"கைரேகை அங்கீகரிக்கப்பட்டது"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"கைரேகைப் பதிவுகள் எதுவும் இல்லை."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"இந்தச் சாதனத்தில் கைரேகை சென்சார் இல்லை."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"சென்சார் தற்காலிகமாக முடக்கப்பட்டுள்ளது."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"சென்சாரைச் சீரமைக்க வேண்டும்"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"கைரேகை <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"கைரேகையைப் பயன்படுத்து"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்து"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index d910224af035..dac4c515d8b7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"మరొక వేలిముద్రను ట్రై చేయండి"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"వెలుతురు అధికంగా ఉంది"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"సర్దుబాటు చేయడానికి ట్రై చేయండి"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"వేలిముద్ర ప్రమాణీకరించబడింది"</string>
@@ -601,6 +603,8 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"ఈ పరికరంలో వేలిముద్ర సెన్సార్ ఎంపిక లేదు."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"సెన్సార్ తాత్కాలికంగా డిజేబుల్ చేయబడింది."</string>
+ <!-- no translation found for fingerprint_error_bad_calibration (374406495079531135) -->
+ <skip />
<string name="fingerprint_name_template" msgid="8941662088160289778">"వేలు <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"వేలిముద్రను ఉపయోగించండి"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"వేలిముద్ర లేదా స్క్రీన్ లాక్‌ను ఉపయోగించండి"</string>
@@ -1458,10 +1462,8 @@
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"ప్యాకేజీల తొలగింపును అభ్యర్థించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"బ్యాటరీ అనుకూలీకరణలను విస్మరించడానికి అడగాలి"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"ఆ యాప్ కోసం బ్యాటరీ అనుకూలీకరణలు విస్మరించేలా అనుమతి కోరడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <!-- no translation found for permlab_queryAllPackages (2928450604653281650) -->
- <skip />
- <!-- no translation found for permdesc_queryAllPackages (5339069855520996010) -->
- <skip />
+ <string name="permlab_queryAllPackages" msgid="2928450604653281650">"అన్ని ప్యాకేజీలను క్వెరీ చేయండి"</string>
+ <string name="permdesc_queryAllPackages" msgid="5339069855520996010">"ఇన్‌స్టాల్ చేసిన అన్ని ప్యాకేజీలను చూడటానికి యాప్‌ను అనుమతించండి."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"విడ్జెట్‌ను జోడించడం సాధ్యపడలేదు."</string>
<string name="ime_action_go" msgid="5536744546326495436">"వెళ్లు"</string>
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 3ecb1dddd916..55e5685b95e5 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -42,4 +42,8 @@
<!-- Allow SystemUI to show the shutdown dialog -->
<bool name="config_showSysuiShutdown">true</bool>
+
+ <!-- Component name of the activity used to inform a user about a sensory being blocked because
+ of privacy settings. -->
+ <string name="config_sensorUseStartedActivity">com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3f9ae3af84ea..b9ab264eec7d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"ลองลายนิ้วมืออื่น"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"สว่างเกินไป"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ลองปรับการวางนิ้ว"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"ตรวจสอบสิทธิ์ลายนิ้วมือแล้ว"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"ไม่มีลายนิ้วมือที่ลงทะเบียน"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"อุปกรณ์นี้ไม่มีเซ็นเซอร์ลายนิ้วมือ"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"ต้องปรับเทียบเซ็นเซอร์"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"นิ้ว <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"ใช้ลายนิ้วมือ"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index edc7427cfdc5..7678869e2a15 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Sumubok ng ibang fingerprint"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Masyadong maliwanag"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Subukang isaayos"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Na-authenticate ang fingerprint"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Walang naka-enroll na fingerprint."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Walang sensor ng fingerprint ang device na ito."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Pansamantalang na-disable ang sensor."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Kailangang i-calibrate ang sensor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Daliri <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Gumamit ng fingerprint"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Gumamit ng fingerprint o lock ng screen"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e5f9fe99de82..2f9a8b616880 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -585,6 +585,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Başka bir parmak izi deneyin"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Çok parlak"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Ayarlamayı deneyin"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Her defasında parmağınızın konumunu biraz değiştirin"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Parmak izi kimlik doğrulaması yapıldı"</string>
@@ -601,6 +602,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Parmak izi kaydedilmedi."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu cihazda parmak izi sensörü yok."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensör geçici olarak devre dışı bırakıldı."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensörün kalibre edilmesi gerekiyor"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"<xliff:g id="FINGERID">%d</xliff:g>. parmak"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Parmak izi kullan"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Parmak izi veya ekran kilidi kullan"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 964c07719f4e..c04e3f0e947e 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -591,6 +591,7 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Спробуйте інший відбиток пальця"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Надто яскраво"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Спробуйте відкоригувати відбиток пальця"</string>
+ <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Щоразу трохи змінюйте положення пальця"</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Відбиток пальця автентифіковано"</string>
@@ -607,6 +608,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Відбитки пальців не зареєстровано."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На цьому пристрої немає сканера відбитків пальців."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчик тимчасово вимкнено."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Потрібно відкалібрувати датчик"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Відбиток пальця <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Доступ за відбитком пальця"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Використовувати відбиток пальця або дані для розблокування екрана"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7f5046b77277..07d683bd4d80 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"دوسرا فنگر پرنٹ آزمائیں"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"کافی روشنی ہے"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"ایڈجسٹ کرنے کی کوشش کریں"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"فنگر پرنٹ کی تصدیق ہو گئی"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"کوئی فنگر پرنٹ مندرج شدہ نہیں ہے۔"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"اس آلہ میں فنگر پرنٹ سینسر نہیں ہے۔"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"سینسر عارضی طور غیر فعال ہے۔"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"سینسر کو کیلیبریشن کی ضرورت ہے"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"فنگر پرنٹ استعمال کریں"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"فنگر پرنٹ یا اسکرین لاک استعمال کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d8769b24eca4..a64c1a860b0e 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Boshqa barmoq izi bilan urining"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Juda yorqin"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Moslashga urining"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Barmoq izi tekshirildi"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Hech qanday barmoq izi qayd qilinmagan."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Bu qurilmada barmoq izi skaneri mavjud emas."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensor vaqtincha faol emas."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Sensorni sozlash kerak"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Barmoq izi <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Barmoq izi ishlatish"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Barmoq izi yoki ekran qulfi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b276ff15552b..669adefd42e0 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Hãy thử một vân tay khác"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Quá sáng"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Hãy thử điều chỉnh"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Đã xác thực vân tay"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Chưa đăng ký vân tay."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Thiết bị này không có cảm biến vân tay."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Đã tạm thời tắt cảm biến."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Cảm biến cần hiệu chỉnh"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Ngón tay <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Dùng vân tay"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Dùng vân tay hoặc phương thức khóa màn hình"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b745661b42c7..ec8a7751e231 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"请试试其他指纹"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"光线太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"请尝试调整指纹"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"已验证指纹"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未注册任何指纹。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此设备没有指纹传感器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"传感器已暂时停用。"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"传感器需要校准"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指纹"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指纹或屏幕锁定凭据"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index fd0bd9f1be77..c91a42677e64 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"嘗試調整"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"驗證咗指紋"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未註冊任何指紋"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"此裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"需要校正感應器"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋鎖定"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 310663f005d6..89b48d68b0c7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"改用其他指紋"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"太亮"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"請試著調整"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"指紋驗證成功"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"未登錄任何指紋。"</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"這個裝置沒有指紋感應器。"</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"感應器已暫時停用。"</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"必須校正感應器"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"手指 <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"使用指紋"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"使用指紋或螢幕鎖定功能"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index ae01829085f3..671f5f7020ca 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -585,6 +585,8 @@
<string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Zama ezinye izigxivizo zeminwe"</string>
<string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Kukhanya kakhulu"</string>
<string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Zama ukulungisa"</string>
+ <!-- no translation found for fingerprint_acquired_immobile (1621891895241888048) -->
+ <skip />
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_authenticated" msgid="2024862866860283100">"Izigxivizo zeminwe zigunyaziwe"</string>
@@ -601,6 +603,7 @@
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Azikho izigxivizo zeminwe ezibhalisiwe."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Le divayisi ayinayo inzwa yezigxivizo zeminwe."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Inzwa ikhutshazwe okwesikhashana."</string>
+ <string name="fingerprint_error_bad_calibration" msgid="374406495079531135">"Inzwa idinga ukulinganisa"</string>
<string name="fingerprint_name_template" msgid="8941662088160289778">"Umunwe ongu-<xliff:g id="FINGERID">%d</xliff:g>"</string>
<string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Sebenzisa izigxivizo zeminwe"</string>
<string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Sebenzisa izigxivizo zeminwe noma ukukhiya isikrini"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3c47366a59db..7c7a89385c5e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1706,6 +1706,10 @@
config_enableFusedLocationOverlay is false. -->
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
+ <!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been
+ set before. -->
+ <bool name="config_defaultAdasGnssLocationEnabled" translatable="false">false</bool>
+
<string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
<!-- The package name of the default network recommendation app.
@@ -3350,6 +3354,10 @@
<!-- The default vibration strength, must be between 1 and 255 inclusive. -->
<integer name="config_defaultVibrationAmplitude">255</integer>
+ <!-- The max vibration strength allowed in audio haptic channels, must be positive or zero if
+ limit is unknown. -->
+ <item name="config_hapticChannelMaxVibrationAmplitude" format="float" type="dimen">0</item>
+
<!-- If the device should still vibrate even in low power mode, for certain priority vibrations
(e.g. accessibility, alarms). This is mainly for Wear devices that don't have speakers. -->
<bool name="config_allowPriorityVibrationsInLowPowerMode">false</bool>
@@ -5003,6 +5011,10 @@
<!-- Default value for Settings.ASSIST_TOUCH_GESTURE_ENABLED -->
<bool name="config_assistTouchGestureEnabledDefault">true</bool>
+ <!-- The maximum byte size of the information contained in the bundle of
+ HotwordDetectedResult. -->
+ <integer translatable="false" name="config_hotwordDetectedResultMaxBundleSize">0</integer>
+
<!-- The amount of dimming to apply to wallpapers with mid range luminance. 0 displays
the wallpaper at full brightness. 1 displays the wallpaper as fully black. -->
<item name="config_wallpaperDimAmount" format="float" type="dimen">0.05</item>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d4ddab1ec502..302bd94c1973 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1603,6 +1603,8 @@
<string name="fingerprint_acquired_too_bright">Too bright</string>
<!-- Message shown during fingerprint acquisition when a fingerprint must be adjusted.[CHAR LIMIT=50] -->
<string name="fingerprint_acquired_try_adjusting">Try adjusting</string>
+ <!-- Message shown during fingerprint acquisition when a fingeprint area has already been captured during enrollment [CHAR LIMIT=100] -->
+ <string name="fingerprint_acquired_immobile">Change the position of your finger slightly each time</string>
<!-- Array containing custom messages shown during fingerprint acquisision from vendor. Vendor is expected to add and translate these strings -->
<string-array name="fingerprint_acquired_vendor">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 960bd639960e..94c65a04e244 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1918,6 +1918,7 @@
<java-symbol type="bool" name="config_tintNotificationActionButtons" />
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
+ <java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" />
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
@@ -2013,6 +2014,7 @@
<java-symbol type="integer" name="config_notificationServiceArchiveSize" />
<java-symbol type="integer" name="config_previousVibrationsDumpLimit" />
<java-symbol type="integer" name="config_defaultVibrationAmplitude" />
+ <java-symbol type="dimen" name="config_hapticChannelMaxVibrationAmplitude" />
<java-symbol type="integer" name="config_vibrationWaveformRampStepDuration" />
<java-symbol type="integer" name="config_vibrationWaveformRampDownDuration" />
<java-symbol type="integer" name="config_radioScanningTimeout" />
@@ -2538,6 +2540,7 @@
<java-symbol type="string" name="fingerprint_error_hw_not_present" />
<java-symbol type="string" name="fingerprint_error_security_update_required" />
<java-symbol type="string" name="fingerprint_error_bad_calibration" />
+ <java-symbol type="string" name="fingerprint_acquired_immobile" />
<!-- Fingerprint config -->
<java-symbol type="integer" name="config_fingerprintMaxTemplatesPerUser"/>
@@ -4402,5 +4405,7 @@
<java-symbol type="bool" name="config_assistLongPressHomeEnabledDefault" />
<java-symbol type="bool" name="config_assistTouchGestureEnabledDefault" />
+ <java-symbol type="integer" name="config_hotwordDetectedResultMaxBundleSize" />
+
<java-symbol type="dimen" name="config_wallpaperDimAmount" />
</resources>
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
index de0670b08ffd..228a061ae3c8 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchResultTest.java
@@ -18,7 +18,7 @@ package android.app.appsearch;
import static com.google.common.truth.Truth.assertThat;
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
import org.junit.Test;
@@ -26,7 +26,7 @@ public class AppSearchResultTest {
@Test
public void testMapNullPointerException() {
NullPointerException e =
- expectThrows(
+ assertThrows(
NullPointerException.class,
() -> {
Object o = null;
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java
deleted file mode 100644
index 6fad4b8dcdac..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/external/app/PutDocumentsRequestTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.app.appsearch;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.android.server.appsearch.testing.AppSearchEmail;
-
-import com.google.common.collect.ImmutableSet;
-
-import org.junit.Test;
-
-import java.util.Set;
-
-public class PutDocumentsRequestTest {
-
- @Test
- public void addGenericDocument_byCollection() {
- Set<AppSearchEmail> emails =
- ImmutableSet.of(
- new AppSearchEmail.Builder("namespace", "test1").build(),
- new AppSearchEmail.Builder("namespace", "test2").build());
- PutDocumentsRequest request =
- new PutDocumentsRequest.Builder().addGenericDocuments(emails).build();
-
- assertThat(request.getGenericDocuments().get(0).getId()).isEqualTo("test1");
- assertThat(request.getGenericDocuments().get(1).getId()).isEqualTo("test2");
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java b/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java
new file mode 100644
index 000000000000..057ecbd9dfe9
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/util/IndentingStringBuilderTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app.appsearch.util;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import org.junit.Test;
+
+public class IndentingStringBuilderTest {
+ @Test
+ public void testAppendIndentedStrings() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ stringBuilder
+ .increaseIndentLevel()
+ .append("\nIndentLevel1\nIndentLevel1\n")
+ .decreaseIndentLevel()
+ .append("IndentLevel0,\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n IndentLevel1\n IndentLevel1\nIndentLevel0,\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testDecreaseIndentLevel_throwsException() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ Exception e =
+ assertThrows(
+ IllegalStateException.class, () -> stringBuilder.decreaseIndentLevel());
+ assertThat(e).hasMessageThat().contains("Cannot set indent level below 0.");
+ }
+
+ @Test
+ public void testAppendIndentedObjects() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+ Object stringProperty = "String";
+ Object longProperty = 1L;
+ Object booleanProperty = true;
+
+ stringBuilder
+ .append(stringProperty)
+ .append("\n")
+ .increaseIndentLevel()
+ .append(longProperty)
+ .append("\n")
+ .decreaseIndentLevel()
+ .append(booleanProperty);
+
+ String str = stringBuilder.toString();
+ String expectedString = "String\n 1\ntrue";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+
+ @Test
+ public void testAppendIndentedStrings_doesNotIndentLineBreak() {
+ IndentingStringBuilder stringBuilder = new IndentingStringBuilder();
+
+ stringBuilder
+ .append("\n")
+ .increaseIndentLevel()
+ .append("\n\n")
+ .decreaseIndentLevel()
+ .append("\n");
+
+ String str = stringBuilder.toString();
+ String expectedString = "\n\n\n\n";
+
+ assertThat(str).isEqualTo(expectedString);
+ }
+}
diff --git a/core/tests/coretests/src/android/os/VibratorInfoTest.java b/core/tests/coretests/src/android/os/VibratorInfoTest.java
index 8c7d10c7a5ef..6e07fa264c1c 100644
--- a/core/tests/coretests/src/android/os/VibratorInfoTest.java
+++ b/core/tests/coretests/src/android/os/VibratorInfoTest.java
@@ -87,14 +87,14 @@ public class VibratorInfoTest {
public void testIsPrimitiveSupported() {
VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
.build();
assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_TICK));
// Returns false when there is no compose capability.
info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
- .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
.build();
assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
}
@@ -103,8 +103,7 @@ public class VibratorInfoTest {
public void testGetPrimitiveDuration() {
VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
- .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
- .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
.build();
assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_TICK));
@@ -113,6 +112,26 @@ public class VibratorInfoTest {
}
@Test
+ public void testCompositionLimits() {
+ VibratorInfo info = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
+ .setPrimitiveDelayMax(100)
+ .setCompositionSizeMax(10)
+ .setPwlePrimitiveDurationMax(50)
+ .setPwleSizeMax(20)
+ .build();
+ assertEquals(100, info.getPrimitiveDelayMax());
+ assertEquals(10, info.getCompositionSizeMax());
+ assertEquals(50, info.getPwlePrimitiveDurationMax());
+ assertEquals(20, info.getPwleSizeMax());
+
+ VibratorInfo emptyInfo = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
+ assertEquals(0, emptyInfo.getPrimitiveDelayMax());
+ assertEquals(0, emptyInfo.getCompositionSizeMax());
+ assertEquals(0, emptyInfo.getPwlePrimitiveDurationMax());
+ assertEquals(0, emptyInfo.getPwleSizeMax());
+ }
+
+ @Test
public void testGetDefaultBraking_returnsFirstSupportedBraking() {
assertEquals(Braking.NONE, new VibratorInfo.Builder(
TEST_VIBRATOR_ID).build().getDefaultBraking());
@@ -263,8 +282,12 @@ public class VibratorInfoTest {
VibratorInfo.Builder completeBuilder = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL)
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
- .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .setPrimitiveDelayMax(100)
+ .setCompositionSizeMax(10)
+ .setSupportedBraking(Braking.CLAB)
+ .setPwlePrimitiveDurationMax(50)
+ .setPwleSizeMax(20)
.setQFactor(2f)
.setFrequencyMapping(TEST_FREQUENCY_MAPPING);
VibratorInfo complete = completeBuilder.build();
@@ -279,8 +302,7 @@ public class VibratorInfoTest {
assertNotEquals(complete, completeWithComposeControl);
VibratorInfo completeWithNoEffects = completeBuilder
- .setSupportedEffects()
- .setSupportedPrimitives()
+ .setSupportedEffects(new int[0])
.build();
assertNotEquals(complete, completeWithNoEffects);
@@ -289,13 +311,8 @@ public class VibratorInfoTest {
.build();
assertNotEquals(complete, completeWithUnknownEffects);
- VibratorInfo completeWithUnknownPrimitives = completeBuilder
- .setSupportedPrimitives(null)
- .build();
- assertNotEquals(complete, completeWithUnknownPrimitives);
-
VibratorInfo completeWithDifferentPrimitiveDuration = completeBuilder
- .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
.build();
assertNotEquals(complete, completeWithDifferentPrimitiveDuration);
@@ -321,12 +338,17 @@ public class VibratorInfoTest {
.build();
assertNotEquals(complete, completeWithDifferentQFactor);
- VibratorInfo empty = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
- VibratorInfo emptyWithKnownSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
- .setSupportedEffects()
- .setSupportedPrimitives()
+ VibratorInfo unknownEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
+ VibratorInfo knownEmptyEffectSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
+ .setSupportedEffects(new int[0])
+ .build();
+ assertNotEquals(unknownEffectSupport, knownEmptyEffectSupport);
+
+ VibratorInfo unknownBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID).build();
+ VibratorInfo knownEmptyBrakingSupport = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
+ .setSupportedBraking(new int[0])
.build();
- assertNotEquals(empty, emptyWithKnownSupport);
+ assertNotEquals(unknownBrakingSupport, knownEmptyBrakingSupport);
}
@Test
@@ -334,8 +356,7 @@ public class VibratorInfoTest {
VibratorInfo original = new VibratorInfo.Builder(TEST_VIBRATOR_ID)
.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
.setSupportedEffects(VibrationEffect.EFFECT_CLICK)
- .setSupportedPrimitives(VibrationEffect.Composition.PRIMITIVE_CLICK)
- .setPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
.setQFactor(Float.NaN)
.setFrequencyMapping(TEST_FREQUENCY_MAPPING)
.build();
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
index 8f9168b58184..0ece793c8125 100644
--- a/core/tests/coretests/src/android/os/VibratorTest.java
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -16,6 +16,8 @@
package android.os;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -26,6 +28,7 @@ import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.hardware.vibrator.IVibrator;
import android.media.AudioAttributes;
import android.platform.test.annotations.Presubmit;
@@ -70,6 +73,54 @@ public class VibratorTest {
}
@Test
+ public void areEffectsSupported_noVibrator_returnsAlwaysNo() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void areEffectsSupported_unsupportedInOneVibrator_returnsNo() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unsupportedVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(new int[0])
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_NO,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void areEffectsSupported_unknownInOneVibrator_returnsUnknown() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo unknownSupportVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unknownSupportVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_UNKNOWN,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_supportedInAllVibrators_returnsYes() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setSupportedEffects(VibrationEffect.EFFECT_CLICK)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertEquals(Vibrator.VIBRATION_EFFECT_SUPPORT_YES,
+ info.isEffectSupported(VibrationEffect.EFFECT_CLICK));
+ }
+
+ @Test
public void arePrimitivesSupported_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.arePrimitivesSupported(new int[0]).length);
assertEquals(1, mVibratorSpy.arePrimitivesSupported(
@@ -80,6 +131,40 @@ public class VibratorTest {
}
@Test
+ public void arePrimitivesSupported_noVibrator_returnsAlwaysFalse() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_unsupportedInOneVibrator_returnsFalse() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertFalse(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void arePrimitivesSupported_supportedInAllVibrators_returnsTrue() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 5)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 15)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertTrue(info.isPrimitiveSupported(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
public void getPrimitivesDurations_returnsArrayOfSameSize() {
assertEquals(0, mVibratorSpy.getPrimitiveDurations(new int[0]).length);
assertEquals(1, mVibratorSpy.getPrimitiveDurations(
@@ -90,6 +175,40 @@ public class VibratorTest {
}
@Test
+ public void getPrimitivesDurations_noVibrator_returnsAlwaysZero() {
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[0]);
+ assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void getPrimitivesDurations_unsupportedInOneVibrator_returnsZero() {
+ VibratorInfo supportedVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo unsupportedVibrator = VibratorInfo.EMPTY_VIBRATOR_INFO;
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{supportedVibrator, unsupportedVibrator});
+ assertEquals(0, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
+ public void getPrimitivesDurations_supportedInAllVibrators_returnsMaxDuration() {
+ VibratorInfo firstVibrator = new VibratorInfo.Builder(/* id= */ 1)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 10)
+ .build();
+ VibratorInfo secondVibrator = new VibratorInfo.Builder(/* id= */ 2)
+ .setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS)
+ .setSupportedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 20)
+ .build();
+ SystemVibrator.AllVibratorsInfo info = new SystemVibrator.AllVibratorsInfo(
+ new VibratorInfo[]{firstVibrator, secondVibrator});
+ assertEquals(20, info.getPrimitiveDuration(VibrationEffect.Composition.PRIMITIVE_CLICK));
+ }
+
+ @Test
public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 89d2b743a619..72a145fa6a05 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -151,7 +151,7 @@ public class AndroidKeyStoreProvider extends Provider {
* Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
* primitive.
*
- * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
+ * <p>The following primitives are supported: {@link Cipher}, {@link Signature} and {@link Mac}.
*
* @return KeyStore operation handle or {@code 0} if the provided primitive's KeyStore operation
* is not in progress.
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 70f03d234a56..f28ee820eb35 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -117,7 +117,9 @@
<!-- This should be at least the size of bubble_expanded_view_padding; it is used to include
a slight touch slop around the expanded view. -->
<dimen name="bubble_expanded_view_slop">8dp</dimen>
- <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded -->
+ <!-- Default (and minimum) height of the expanded view shown when the bubble is expanded.
+ If this value changes then R.dimen.bubble_expanded_view_min_height in CtsVerifier
+ should also be updated. -->
<dimen name="bubble_expanded_default_height">180dp</dimen>
<!-- On large screens the width of the expanded view is restricted to this size. -->
<dimen name="bubble_expanded_view_tablet_width">412dp</dimen>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 7e673c6e32c2..b5c54023c492 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -482,7 +482,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController>
@VisibleForTesting
void notifyExpandNotification() {
- mMainExecutor.execute(() -> mEventCallback.notifyExpandNotification());
+ if (mEventCallback != null) {
+ mMainExecutor.execute(() -> mEventCallback.notifyExpandNotification());
+ }
}
@VisibleForTesting
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 1a365fee3b13..9986154b051d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -235,7 +235,8 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
}
void onAnimationProgress(float linearProgress) {
- if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) {
+ if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()
+ || !mSplashScreenView.isAttachedToWindow()) {
return;
}
@@ -267,15 +268,20 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
return;
}
final SurfaceControl.Transaction tx = mTransactionPool.acquire();
- tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
-
- SyncRtSurfaceTransactionApplier.SurfaceParams
- params = new SyncRtSurfaceTransactionApplier.SurfaceParams
- .Builder(mFirstWindowSurface)
- .withWindowCrop(null)
- .withMergeTransaction(tx)
- .build();
- mApplier.scheduleApply(params);
+ if (mSplashScreenView.isAttachedToWindow()) {
+ tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+
+ SyncRtSurfaceTransactionApplier.SurfaceParams
+ params = new SyncRtSurfaceTransactionApplier.SurfaceParams
+ .Builder(mFirstWindowSurface)
+ .withWindowCrop(null)
+ .withMergeTransaction(tx)
+ .build();
+ mApplier.scheduleApply(params);
+ } else {
+ tx.setWindowCrop(mFirstWindowSurface, null);
+ tx.apply();
+ }
mTransactionPool.release(tx);
Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT,
@@ -287,13 +293,14 @@ public class SplashScreenExitAnimation implements Animator.AnimatorListener {
if (DEBUG_EXIT_ANIMATION) {
Slog.v(TAG, "vanish animation finished");
}
- mSplashScreenView.post(() -> {
+
+ if (mSplashScreenView.isAttachedToWindow()) {
mSplashScreenView.setVisibility(GONE);
if (mFinishCallback != null) {
mFinishCallback.run();
mFinishCallback = null;
}
- });
+ }
if (mShiftUpAnimation != null) {
mShiftUpAnimation.finish();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 46db35a6e29f..670af963230a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -288,6 +288,7 @@ public class StartingSurfaceDrawer {
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
final FrameLayout rootLayout = new FrameLayout(context);
+ rootLayout.setPadding(0, 0, 0, 0);
final Runnable setViewSynchronized = () -> {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "addSplashScreenView");
// waiting for setContentView before relayoutWindow
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index 47789b7490ee..950900337918 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -435,4 +435,17 @@ public class OneHandedControllerTest extends OneHandedTestCase {
verify(mSpiedOneHandedController).notifyShortcutState(anyInt());
}
+
+ @Test
+ public void testNotifyExpandNotification_withNullCheckProtection() {
+ when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false);
+ when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE);
+ when(mSpiedTransitionState.isTransitioning()).thenReturn(false);
+ when(mSpiedOneHandedController.isSwipeToNotificationEnabled()).thenReturn(true);
+ mSpiedOneHandedController.setOneHandedEnabled(true);
+ mSpiedOneHandedController.notifyExpandNotification();
+
+ // Verify no NPE crash and mMockShellMainExecutor never be execute.
+ verify(mMockShellMainExecutor, never()).execute(any());
+ }
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c770150650e2..45a4f6c9c70d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -331,6 +331,8 @@ public:
mSkiaLayer.reset();
}
+ mProperties.mutateLayerProperties().mutableStretchEffect().clear();
+ mStretchMask.clear();
// Clear out the previous snapshot and the image filter the previous
// snapshot was created with whenever the layer changes.
mSnapshotResult.snapshot = nullptr;
diff --git a/libs/hwui/effects/StretchEffect.cpp b/libs/hwui/effects/StretchEffect.cpp
index 43f805d906a5..17cd3ceb577c 100644
--- a/libs/hwui/effects/StretchEffect.cpp
+++ b/libs/hwui/effects/StretchEffect.cpp
@@ -186,6 +186,7 @@ static const SkString stretchShader = SkString(R"(
static const float ZERO = 0.f;
static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
+static const char CONTENT_TEXTURE[] = "uContentTexture";
sk_sp<SkShader> StretchEffect::getShader(float width, float height,
const sk_sp<SkImage>& snapshotImage,
@@ -207,7 +208,7 @@ sk_sp<SkShader> StretchEffect::getShader(float width, float height,
mBuilder = std::make_unique<SkRuntimeShaderBuilder>(getStretchEffect());
}
- mBuilder->child("uContentTexture") =
+ mBuilder->child(CONTENT_TEXTURE) =
snapshotImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
SkSamplingOptions(SkFilterMode::kLinear), matrix);
mBuilder->uniform("uInterpolationStrength").set(&INTERPOLATION_STRENGTH_VALUE, 1);
@@ -226,7 +227,9 @@ sk_sp<SkShader> StretchEffect::getShader(float width, float height,
mBuilder->uniform("viewportWidth").set(&width, 1);
mBuilder->uniform("viewportHeight").set(&height, 1);
- return mBuilder->makeShader(nullptr, false);
+ auto result = mBuilder->makeShader(nullptr, false);
+ mBuilder->child(CONTENT_TEXTURE) = nullptr;
+ return result;
}
sk_sp<SkRuntimeEffect> StretchEffect::getStretchEffect() {
diff --git a/libs/hwui/effects/StretchEffect.h b/libs/hwui/effects/StretchEffect.h
index 25777c278a11..3eab9f05ebe5 100644
--- a/libs/hwui/effects/StretchEffect.h
+++ b/libs/hwui/effects/StretchEffect.h
@@ -113,6 +113,10 @@ public:
return !isEmpty();
}
+ void clear() {
+ mBuilder = nullptr;
+ }
+
private:
static sk_sp<SkRuntimeEffect> getStretchEffect();
mutable SkVector mStretchDirection{0, 0};
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 4cd3616566c2..ecdd4b616e0f 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -214,6 +214,25 @@ public final class GnssMeasurement implements Parcelable {
*
* <p> When this bit is unset, the {@link #getAccumulatedDeltaRangeMeters()} corresponds to the
* carrier phase measurement plus an accumulated integer number of carrier half cycles.
+ *
+ * <p> For signals that have databits, the carrier phase tracking loops typically use a costas
+ * loop discriminator. This type of tracking loop introduces a half-cycle ambiguity that is
+ * resolved by searching through the received data for known patterns of databits (e.g. GPS uses
+ * the TLM word) which then determines the polarity of the incoming data and resolves the
+ * half-cycle ambiguity.
+ *
+ * <p>Before the half-cycle ambiguity has been resolved it is possible that the ADR_STATE_VALID
+ * flag is set:
+ *
+ * <ul>
+ * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is not set, the
+ * ADR_STATE_HALF_CYCLE_RESOLVED flag will not be available. Here, a half wave length will be
+ * added to the returned accumulated delta range uncertainty to indicate the half cycle
+ * ambiguity.
+ * <li> In cases where ADR_STATE_HALF_CYCLE_REPORTED is set, half cycle ambiguity will be
+ * indicated via both the ADR_STATE_HALF_CYCLE_RESOLVED flag and as well a half wave length
+ * added to the returned accumulated delta range uncertainty.
+ * </ul>
*/
public static final int ADR_STATE_HALF_CYCLE_RESOLVED = (1<<3);
@@ -1039,9 +1058,6 @@ public final class GnssMeasurement implements Parcelable {
* with integer ambiguity resolution, to determine highly precise relative location between
* receivers.
*
- * <p>This includes ensuring that all half-cycle ambiguities are resolved before this value is
- * reported as {@link #ADR_STATE_VALID}.
- *
* <p>The alignment of the phase measurement will not be adjusted by the receiver so the
* in-phase and quadrature phase components will have a quarter cycle offset as they do when
* transmitted from the satellites. If the measurement is from a combination of the in-phase
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c9e4e0a9cb92..5d5c0fc6265d 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -122,6 +122,9 @@ interface ILocationManager
boolean isLocationEnabledForUser(int userId);
void setLocationEnabledForUser(boolean enabled, int userId);
+ boolean isAdasGnssLocationEnabledForUser(int userId);
+ void setAdasGnssLocationEnabledForUser(boolean enabled, int userId);
+
void addTestProvider(String name, in ProviderProperties properties,
in List<String> locationTags, String packageName, @nullable String attributionTag);
void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
index 9ea8048ad476..0970c1c76a36 100644
--- a/location/java/android/location/LastLocationRequest.java
+++ b/location/java/android/location/LastLocationRequest.java
@@ -34,12 +34,15 @@ import java.util.Objects;
public final class LastLocationRequest implements Parcelable {
private final boolean mHiddenFromAppOps;
+ private final boolean mAdasGnssBypass;
private final boolean mLocationSettingsIgnored;
private LastLocationRequest(
boolean hiddenFromAppOps,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored) {
mHiddenFromAppOps = hiddenFromAppOps;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
}
@@ -56,6 +59,21 @@ public final class LastLocationRequest implements Parcelable {
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @return true if all limiting factors will be ignored to satisfy GNSS request
+ * @hide
+ */
+ // TODO: make this system api
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+
+ /**
* Returns true if location settings, throttling, background location limits, and any other
* possible limiting factors will be ignored in order to satisfy this last location request.
*
@@ -65,12 +83,22 @@ public final class LastLocationRequest implements Parcelable {
return mLocationSettingsIgnored;
}
+ /**
+ * Returns true if any bypass flag is set on this request. For internal use only.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
new Parcelable.Creator<LastLocationRequest>() {
@Override
public LastLocationRequest createFromParcel(Parcel in) {
return new LastLocationRequest(
/* hiddenFromAppOps= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean());
}
@Override
@@ -86,6 +114,7 @@ public final class LastLocationRequest implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeBoolean(mHiddenFromAppOps);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
}
@@ -99,12 +128,13 @@ public final class LastLocationRequest implements Parcelable {
}
LastLocationRequest that = (LastLocationRequest) o;
return mHiddenFromAppOps == that.mHiddenFromAppOps
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored;
}
@Override
public int hashCode() {
- return Objects.hash(mHiddenFromAppOps, mLocationSettingsIgnored);
+ return Objects.hash(mHiddenFromAppOps, mAdasGnssBypass, mLocationSettingsIgnored);
}
@NonNull
@@ -115,8 +145,11 @@ public final class LastLocationRequest implements Parcelable {
if (mHiddenFromAppOps) {
s.append("hiddenFromAppOps, ");
}
+ if (mAdasGnssBypass) {
+ s.append("adasGnssBypass, ");
+ }
if (mLocationSettingsIgnored) {
- s.append("locationSettingsIgnored, ");
+ s.append("settingsBypass, ");
}
if (s.length() > "LastLocationRequest[".length()) {
s.setLength(s.length() - 2);
@@ -131,6 +164,7 @@ public final class LastLocationRequest implements Parcelable {
public static final class Builder {
private boolean mHiddenFromAppOps;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
/**
@@ -138,6 +172,7 @@ public final class LastLocationRequest implements Parcelable {
*/
public Builder() {
mHiddenFromAppOps = false;
+ mAdasGnssBypass = false;
mLocationSettingsIgnored = false;
}
@@ -146,6 +181,7 @@ public final class LastLocationRequest implements Parcelable {
*/
public Builder(@NonNull LastLocationRequest lastLocationRequest) {
mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
+ mAdasGnssBypass = lastLocationRequest.mAdasGnssBypass;
mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
}
@@ -164,6 +200,25 @@ public final class LastLocationRequest implements Parcelable {
}
/**
+ * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
+ * Systems) client, which requires access to GNSS even if location settings would normally
+ * deny this, in order to enable auto safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS
+ * application. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ // TODO: make this system api
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* If set to true, indicates that location settings, throttling, background location limits,
* and any other possible limiting factors should be ignored in order to satisfy this
* last location request. This is only intended for use in user initiated emergency
@@ -186,6 +241,7 @@ public final class LastLocationRequest implements Parcelable {
public @NonNull LastLocationRequest build() {
return new LastLocationRequest(
mHiddenFromAppOps,
+ mAdasGnssBypass,
mLocationSettingsIgnored);
}
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ae44c5e34521..526b84e85e38 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -315,6 +315,33 @@ public class LocationManager {
public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
/**
+ * Broadcast intent action when the ADAS (Advanced Driving Assistance Systems) GNSS location
+ * enabled state changes. Includes a boolean intent extra, {@link #EXTRA_ADAS_GNSS_ENABLED},
+ * with the enabled state of ADAS GNSS location. This broadcast only has meaning on automotive
+ * devices.
+ *
+ * @see #EXTRA_ADAS_GNSS_ENABLED
+ * @see #isAdasGnssLocationEnabled()
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED =
+ "android.location.action.ADAS_GNSS_ENABLED_CHANGED";
+
+ /**
+ * Intent extra included with {@link #ACTION_ADAS_GNSS_ENABLED_CHANGED} broadcasts, containing
+ * the boolean enabled state of ADAS GNSS location.
+ *
+ * @see #ACTION_ADAS_GNSS_ENABLED_CHANGED
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
+
+ /**
* Broadcast intent action indicating that a high power location requests
* has either started or stopped being active. The current state of
* active location requests should be read from AppOpsManager using
@@ -621,6 +648,42 @@ public class LocationManager {
}
/**
+ * Returns the current enabled/disabled state of ADAS (Advanced Driving Assistance Systems)
+ * GNSS location access for the given user. This controls safety critical automotive access to
+ * GNSS location. This only has meaning on automotive devices.
+ *
+ * @return true if ADAS location is enabled and false if ADAS location is disabled.
+ *
+ * @hide
+ */
+ //TODO: @SystemApi
+ public boolean isAdasGnssLocationEnabled() {
+ try {
+ return mService.isAdasGnssLocationEnabledForUser(mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Enables or disables ADAS (Advanced Driving Assistance Systems) GNSS location access for the
+ * given user. This only has meaning on automotive devices.
+ *
+ * @param enabled true to enable ADAS location and false to disable ADAS location.
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @RequiresPermission(WRITE_SECURE_SETTINGS)
+ public void setAdasGnssLocationEnabled(boolean enabled) {
+ try {
+ mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the current enabled/disabled status of the given provider. To listen for changes, see
* {@link #PROVIDERS_CHANGED_ACTION}.
*
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index a3842a1ffd0a..b48e59676ac1 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -194,6 +194,7 @@ public final class LocationRequest implements Parcelable {
private float mMinUpdateDistanceMeters;
private final long mMaxUpdateDelayMillis;
private boolean mHideFromAppOps;
+ private final boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
private @Nullable WorkSource mWorkSource;
@@ -236,7 +237,7 @@ public final class LocationRequest implements Parcelable {
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
quality = POWER_NONE;
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
- quality = ACCURACY_FINE;
+ quality = QUALITY_HIGH_ACCURACY;
} else {
quality = POWER_LOW;
}
@@ -289,6 +290,7 @@ public final class LocationRequest implements Parcelable {
float minUpdateDistanceMeters,
long maxUpdateDelayMillis,
boolean hiddenFromAppOps,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored,
boolean lowPower,
WorkSource workSource) {
@@ -302,8 +304,9 @@ public final class LocationRequest implements Parcelable {
mMinUpdateDistanceMeters = minUpdateDistanceMeters;
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mHideFromAppOps = hiddenFromAppOps;
- mLowPower = lowPower;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
+ mLowPower = lowPower;
mWorkSource = Objects.requireNonNull(workSource);
}
@@ -339,15 +342,15 @@ public final class LocationRequest implements Parcelable {
switch (quality) {
case POWER_HIGH:
// fall through
- case ACCURACY_FINE:
+ case QUALITY_HIGH_ACCURACY:
mQuality = QUALITY_HIGH_ACCURACY;
break;
- case ACCURACY_BLOCK:
+ case QUALITY_BALANCED_POWER_ACCURACY:
mQuality = QUALITY_BALANCED_POWER_ACCURACY;
break;
case POWER_LOW:
// fall through
- case ACCURACY_CITY:
+ case QUALITY_LOW_POWER:
mQuality = QUALITY_LOW_POWER;
break;
case POWER_NONE:
@@ -648,6 +651,21 @@ public final class LocationRequest implements Parcelable {
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @return true if all limiting factors will be ignored to satisfy GNSS request
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+ /**
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
@@ -673,6 +691,15 @@ public final class LocationRequest implements Parcelable {
}
/**
+ * Returns true if any bypass flag is set on this request. For internal use only.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
+ /**
* @hide
* @deprecated LocationRequests should be treated as immutable.
*/
@@ -749,6 +776,7 @@ public final class LocationRequest implements Parcelable {
/* minUpdateDistanceMeters= */ in.readFloat(),
/* maxUpdateDelayMillis= */ in.readLong(),
/* hiddenFromAppOps= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* lowPower= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
@@ -777,6 +805,7 @@ public final class LocationRequest implements Parcelable {
parcel.writeFloat(mMinUpdateDistanceMeters);
parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mHideFromAppOps);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeBoolean(mLowPower);
parcel.writeTypedObject(mWorkSource, 0);
@@ -801,6 +830,7 @@ public final class LocationRequest implements Parcelable {
&& Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mHideFromAppOps == that.mHideFromAppOps
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mLowPower == that.mLowPower
&& Objects.equals(mProvider, that.mProvider)
@@ -866,8 +896,11 @@ public final class LocationRequest implements Parcelable {
if (mHideFromAppOps) {
s.append(", hiddenFromAppOps");
}
+ if (mAdasGnssBypass) {
+ s.append(", adasGnssBypass");
+ }
if (mLocationSettingsIgnored) {
- s.append(", locationSettingsIgnored");
+ s.append(", settingsBypass");
}
if (mWorkSource != null && !mWorkSource.isEmpty()) {
s.append(", ").append(mWorkSource);
@@ -889,6 +922,7 @@ public final class LocationRequest implements Parcelable {
private float mMinUpdateDistanceMeters;
private long mMaxUpdateDelayMillis;
private boolean mHiddenFromAppOps;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private boolean mLowPower;
@Nullable private WorkSource mWorkSource;
@@ -908,6 +942,7 @@ public final class LocationRequest implements Parcelable {
mMinUpdateDistanceMeters = 0;
mMaxUpdateDelayMillis = 0;
mHiddenFromAppOps = false;
+ mAdasGnssBypass = false;
mLocationSettingsIgnored = false;
mLowPower = false;
mWorkSource = null;
@@ -925,6 +960,7 @@ public final class LocationRequest implements Parcelable {
mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
mHiddenFromAppOps = locationRequest.mHideFromAppOps;
+ mAdasGnssBypass = locationRequest.mAdasGnssBypass;
mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
mLowPower = locationRequest.mLowPower;
mWorkSource = locationRequest.mWorkSource;
@@ -977,10 +1013,10 @@ public final class LocationRequest implements Parcelable {
public @NonNull Builder setQuality(@NonNull Criteria criteria) {
switch (criteria.getAccuracy()) {
case Criteria.ACCURACY_COARSE:
- mQuality = ACCURACY_BLOCK;
+ mQuality = QUALITY_BALANCED_POWER_ACCURACY;
break;
case Criteria.ACCURACY_FINE:
- mQuality = ACCURACY_FINE;
+ mQuality = QUALITY_HIGH_ACCURACY;
break;
default: {
if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
@@ -1092,6 +1128,25 @@ public final class LocationRequest implements Parcelable {
}
/**
+ * If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
+ * Systems) client, which requires access to GNSS even if location settings would normally
+ * deny this, in order to enable auto safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS
+ * application. Defaults to false.
+ *
+ * <p>Permissions enforcement occurs when resulting location request is actually used, not
+ * when this method is invoked.
+ *
+ * @hide
+ */
+ // TODO: @SystemApi
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* If set to true, indicates that location settings, throttling, background location limits,
* and any other possible limiting factors should be ignored in order to satisfy this
* request. This is only intended for use in user initiated emergency situations, and
@@ -1171,6 +1226,7 @@ public final class LocationRequest implements Parcelable {
mMinUpdateDistanceMeters,
mMaxUpdateDelayMillis,
mHiddenFromAppOps,
+ mAdasGnssBypass,
mLocationSettingsIgnored,
mLowPower,
new WorkSource(mWorkSource));
diff --git a/location/java/android/location/provider/ProviderRequest.java b/location/java/android/location/provider/ProviderRequest.java
index b72d36519e72..4f33a529a812 100644
--- a/location/java/android/location/provider/ProviderRequest.java
+++ b/location/java/android/location/provider/ProviderRequest.java
@@ -44,12 +44,19 @@ public final class ProviderRequest implements Parcelable {
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
public static final @NonNull ProviderRequest EMPTY_REQUEST = new ProviderRequest(
- INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, 0, false, false, new WorkSource());
+ INTERVAL_DISABLED,
+ QUALITY_BALANCED_POWER_ACCURACY,
+ 0,
+ false,
+ false,
+ false,
+ new WorkSource());
private final long mIntervalMillis;
private final @Quality int mQuality;
private final long mMaxUpdateDelayMillis;
private final boolean mLowPower;
+ private final boolean mAdasGnssBypass;
private final boolean mLocationSettingsIgnored;
private final WorkSource mWorkSource;
@@ -72,12 +79,14 @@ public final class ProviderRequest implements Parcelable {
@Quality int quality,
long maxUpdateDelayMillis,
boolean lowPower,
+ boolean adasGnssBypass,
boolean locationSettingsIgnored,
@NonNull WorkSource workSource) {
mIntervalMillis = intervalMillis;
mQuality = quality;
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
mLowPower = lowPower;
+ mAdasGnssBypass = adasGnssBypass;
mLocationSettingsIgnored = locationSettingsIgnored;
mWorkSource = Objects.requireNonNull(workSource);
}
@@ -126,6 +135,18 @@ public final class ProviderRequest implements Parcelable {
}
/**
+ * Returns true if this request may access GNSS even if location settings would normally deny
+ * this, in order to enable automotive safety features. This field is only respected on
+ * automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
+ * Driving Assistance Systems) application.
+ *
+ * @hide
+ */
+ public boolean isAdasGnssBypass() {
+ return mAdasGnssBypass;
+ }
+
+ /**
* Whether the provider should ignore all location settings, user consents, power restrictions
* or any other restricting factors and always satisfy this request to the best of their
* ability. This should only be used in case of a user initiated emergency.
@@ -135,6 +156,15 @@ public final class ProviderRequest implements Parcelable {
}
/**
+ * Returns true if any bypass flag is set on this request.
+ *
+ * @hide
+ */
+ public boolean isBypass() {
+ return mAdasGnssBypass || mLocationSettingsIgnored;
+ }
+
+ /**
* The power blame for this provider request.
*/
public @NonNull WorkSource getWorkSource() {
@@ -153,6 +183,7 @@ public final class ProviderRequest implements Parcelable {
/* quality= */ in.readInt(),
/* maxUpdateDelayMillis= */ in.readLong(),
/* lowPower= */ in.readBoolean(),
+ /* adasGnssBypass= */ in.readBoolean(),
/* locationSettingsIgnored= */ in.readBoolean(),
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
}
@@ -176,6 +207,7 @@ public final class ProviderRequest implements Parcelable {
parcel.writeInt(mQuality);
parcel.writeLong(mMaxUpdateDelayMillis);
parcel.writeBoolean(mLowPower);
+ parcel.writeBoolean(mAdasGnssBypass);
parcel.writeBoolean(mLocationSettingsIgnored);
parcel.writeTypedObject(mWorkSource, flags);
}
@@ -198,6 +230,7 @@ public final class ProviderRequest implements Parcelable {
&& mQuality == that.mQuality
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
&& mLowPower == that.mLowPower
+ && mAdasGnssBypass == that.mAdasGnssBypass
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
&& mWorkSource.equals(that.mWorkSource);
}
@@ -229,8 +262,11 @@ public final class ProviderRequest implements Parcelable {
if (mLowPower) {
s.append(", lowPower");
}
+ if (mAdasGnssBypass) {
+ s.append(", adasGnssBypass");
+ }
if (mLocationSettingsIgnored) {
- s.append(", locationSettingsIgnored");
+ s.append(", settingsBypass");
}
if (!mWorkSource.isEmpty()) {
s.append(", ").append(mWorkSource);
@@ -246,10 +282,12 @@ public final class ProviderRequest implements Parcelable {
* A Builder for {@link ProviderRequest}s.
*/
public static final class Builder {
+
private long mIntervalMillis = INTERVAL_DISABLED;
private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
private long mMaxUpdateDelayMillis = 0;
private boolean mLowPower;
+ private boolean mAdasGnssBypass;
private boolean mLocationSettingsIgnored;
private WorkSource mWorkSource = new WorkSource();
@@ -299,6 +337,16 @@ public final class ProviderRequest implements Parcelable {
}
/**
+ * Sets whether this ADAS request should bypass GNSS settings. False by default.
+ *
+ * @hide
+ */
+ public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
+ this.mAdasGnssBypass = adasGnssBypass;
+ return this;
+ }
+
+ /**
* Sets whether location settings should be ignored. False by default.
*/
public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) {
@@ -326,6 +374,7 @@ public final class ProviderRequest implements Parcelable {
mQuality,
mMaxUpdateDelayMillis,
mLowPower,
+ mAdasGnssBypass,
mLocationSettingsIgnored,
mWorkSource);
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 860d88afe4a2..d8f48c2cf0c6 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -101,6 +101,8 @@ public class MtpDatabase implements AutoCloseable {
private int mBatteryLevel;
private int mBatteryScale;
private int mDeviceType;
+ private String mHostType;
+ private boolean mSkipThumbForHost = false;
private MtpServer mServer;
private MtpStorageManager mManager;
@@ -192,6 +194,7 @@ public class MtpDatabase implements AutoCloseable {
MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE,
MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL,
MtpConstants.DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE,
+ MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
};
@VisibleForNative
@@ -408,6 +411,8 @@ public class MtpDatabase implements AutoCloseable {
}
context.deleteDatabase(devicePropertiesName);
}
+ mHostType = "";
+ mSkipThumbForHost = false;
}
@VisibleForNative
@@ -672,12 +677,24 @@ public class MtpDatabase implements AutoCloseable {
@VisibleForNative
private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) {
+ int length;
+ String value;
+
switch (property) {
case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
// writable string properties kept in shared preferences
- String value = mDeviceProperties.getString(Integer.toString(property), "");
- int length = value.length();
+ value = mDeviceProperties.getString(Integer.toString(property), "");
+ length = value.length();
+ if (length > 255) {
+ length = 255;
+ }
+ value.getChars(0, length, outStringValue, 0);
+ outStringValue[length] = 0;
+ return MtpConstants.RESPONSE_OK;
+ case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
+ value = mHostType;
+ length = value.length();
if (length > 255) {
length = 255;
}
@@ -717,6 +734,14 @@ public class MtpDatabase implements AutoCloseable {
e.putString(Integer.toString(property), stringValue);
return (e.commit() ? MtpConstants.RESPONSE_OK
: MtpConstants.RESPONSE_GENERAL_ERROR);
+ case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
+ mHostType = stringValue;
+ if (stringValue.startsWith("Android/")) {
+ Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+ + "=" + stringValue);
+ mSkipThumbForHost = true;
+ }
+ return MtpConstants.RESPONSE_OK;
}
return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
@@ -838,6 +863,10 @@ public class MtpDatabase implements AutoCloseable {
outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0;
outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0);
outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0);
+ if (mSkipThumbForHost) {
+ Log.d(TAG, "getThumbnailInfo: Skip runtime thumbnail.");
+ return true;
+ }
if (exif.getThumbnailRange() != null) {
if ((outLongs[0] == 0) || (outLongs[1] == 0) || (outLongs[2] == 0)) {
Log.d(TAG, "getThumbnailInfo: check thumb info:"
@@ -880,6 +909,10 @@ public class MtpDatabase implements AutoCloseable {
try {
ExifInterface exif = new ExifInterface(path);
+ if (mSkipThumbForHost) {
+ Log.d(TAG, "getThumbnailData: Skip runtime thumbnail.");
+ return exif.getThumbnail();
+ }
if (exif.getThumbnailRange() != null)
return exif.getThumbnail();
} catch (IOException e) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index e8b04edb2e1b..ec925918d4e6 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -170,6 +170,18 @@ public final class MtpDevice {
}
/**
+ * Set device property SESSION_INITIATOR_VERSION_INFO
+ *
+ * @param propertyStr string value for device property SESSION_INITIATOR_VERSION_INFO
+ * @return -1 for error, 0 for success
+ *
+ * {@hide}
+ */
+ public int setDevicePropertyInitVersion(@NonNull String propertyStr) {
+ return native_set_device_property_init_version(propertyStr);
+ }
+
+ /**
* Returns the list of IDs for all storage units on this device
* Information about each storage unit can be accessed via {@link #getStorageInfo}.
*
@@ -421,6 +433,7 @@ public final class MtpDevice {
private native boolean native_open(String deviceName, int fd);
private native void native_close();
private native MtpDeviceInfo native_get_device_info();
+ private native int native_set_device_property_init_version(String propertyStr);
private native int[] native_get_storage_ids();
private native MtpStorageInfo native_get_storage_info(int storageId);
private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java
index 0304ee386ace..88514515eabf 100644
--- a/media/java/android/mtp/MtpDeviceInfo.java
+++ b/media/java/android/mtp/MtpDeviceInfo.java
@@ -31,6 +31,7 @@ public class MtpDeviceInfo {
private String mSerialNumber;
private int[] mOperationsSupported;
private int[] mEventsSupported;
+ private int[] mDevicePropertySupported;
// only instantiated via JNI
private MtpDeviceInfo() {
@@ -144,6 +145,21 @@ public class MtpDeviceInfo {
}
/**
+ * Returns Device property code supported by the device.
+ *
+ * @return supported Device property code. Can be null if device does not provide the property.
+ *
+ * @see MtpConstants#DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER
+ * @see MtpConstants#DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME
+ * @see MtpConstants#DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO
+ *
+ * {@hide}
+ */
+ public final @NonNull int[] getDevicePropertySupported() {
+ return mDevicePropertySupported;
+ }
+
+ /**
* Returns if the given operation is supported by the device or not.
* @param code Operation code.
* @return If the given operation is supported by the device or not.
@@ -162,6 +178,17 @@ public class MtpDeviceInfo {
}
/**
+ * Returns if the given Device property is supported by the device or not.
+ * @param code Device property code.
+ * @return If the given Device property is supported by the device or not.
+ *
+ * {@hide}
+ */
+ public boolean isDevicePropertySupported(int code) {
+ return isSupported(mDevicePropertySupported, code);
+ }
+
+ /**
* Returns if the code set contains code.
* @hide
*/
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index ffed4747d3ea..a77bc9fe0570 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -1131,6 +1131,7 @@ static const PropertyTableEntry kDevicePropertyTable[] = {
{ MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
{ MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
{ MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 },
+ { MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO, MTP_TYPE_STR },
};
bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
@@ -1289,6 +1290,7 @@ MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
switch (property) {
case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
+ case MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
writable = true;
// fall through
FALLTHROUGH_INTENDED;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 3d2b00fec26c..ac89fecd9150 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -72,6 +72,7 @@ static jfieldID field_deviceInfo_version;
static jfieldID field_deviceInfo_serialNumber;
static jfieldID field_deviceInfo_operationsSupported;
static jfieldID field_deviceInfo_eventsSupported;
+static jfieldID field_deviceInfo_devicePropertySupported;
// MtpStorageInfo fields
static jfieldID field_storageInfo_storageId;
@@ -129,6 +130,8 @@ static void initializeJavaIDs(JNIEnv* env) {
GetFieldIDOrDie(env, clazz_deviceInfo, "mOperationsSupported", "[I");
field_deviceInfo_eventsSupported =
GetFieldIDOrDie(env, clazz_deviceInfo, "mEventsSupported", "[I");
+ field_deviceInfo_devicePropertySupported =
+ GetFieldIDOrDie(env, clazz_deviceInfo, "mDevicePropertySupported", "[I");
clazz_storageInfo =
(jclass)env->NewGlobalRef(FindClassOrDie(env, "android/mtp/MtpStorageInfo"));
@@ -377,9 +380,65 @@ android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz)
}
}
+ assert(deviceInfo->mDeviceProperties);
+ {
+ const size_t size = deviceInfo->mDeviceProperties->size();
+ ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size)));
+ {
+ ScopedIntArrayRW elements(env, events.get());
+ if (elements.get() == NULL) {
+ ALOGE("Could not create devicePropertySupported element.");
+ return NULL;
+ }
+ for (size_t i = 0; i < size; ++i) {
+ elements[i] = static_cast<int>(deviceInfo->mDeviceProperties->at(i));
+ }
+ env->SetObjectField(info, field_deviceInfo_devicePropertySupported, events.get());
+ }
+ }
+
return info;
}
+static jint
+android_mtp_MtpDevice_set_device_property_init_version(JNIEnv *env, jobject thiz,
+ jstring property_str) {
+ MtpDevice* const device = get_device_from_object(env, thiz);
+
+ if (!device) {
+ ALOGD("%s device is null\n", __func__);
+ env->ThrowNew(clazz_io_exception, "Failed to obtain MtpDevice.");
+ return -1;
+ }
+
+ const char *propertyStr = env->GetStringUTFChars(property_str, NULL);
+ if (propertyStr == NULL) {
+ return -1;
+ }
+
+ MtpProperty* property = new MtpProperty(MTP_DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO,
+ MTP_TYPE_STR, true);
+ if (!property) {
+ env->ThrowNew(clazz_io_exception, "Failed to obtain property.");
+ return -1;
+ }
+
+ if (property->getDataType() != MTP_TYPE_STR) {
+ env->ThrowNew(clazz_io_exception, "Unexpected property data type.");
+ return -1;
+ }
+
+ property->setCurrentValue(propertyStr);
+ if (!device->setDevicePropValueStr(property)) {
+ env->ThrowNew(clazz_io_exception, "Failed to obtain property value.");
+ return -1;
+ }
+
+ env->ReleaseStringUTFChars(property_str, propertyStr);
+
+ return 0;
+}
+
static jintArray
android_mtp_MtpDevice_get_storage_ids(JNIEnv *env, jobject thiz)
{
@@ -847,6 +906,8 @@ static const JNINativeMethod gMethods[] = {
{"native_close", "()V", (void *)android_mtp_MtpDevice_close},
{"native_get_device_info", "()Landroid/mtp/MtpDeviceInfo;",
(void *)android_mtp_MtpDevice_get_device_info},
+ {"native_set_device_property_init_version", "(Ljava/lang/String;)I",
+ (void *)android_mtp_MtpDevice_set_device_property_init_version},
{"native_get_storage_ids", "()[I", (void *)android_mtp_MtpDevice_get_storage_ids},
{"native_get_storage_info", "(I)Landroid/mtp/MtpStorageInfo;",
(void *)android_mtp_MtpDevice_get_storage_info},
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 478297f2a3c9..843793ad98f8 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -34,6 +34,8 @@
package javax.obex;
+import android.util.Log;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -43,7 +45,6 @@ import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
-import android.util.Log;
/**
* This class defines a set of helper methods for the implementation of Obex.
@@ -1083,11 +1084,12 @@ public final class ObexHelper {
}
private static int validateMaxPacketSize(int size) {
- if(VDBG && (size > MAX_PACKET_SIZE_INT)) Log.w(TAG,
- "The packet size supported for the connection (" + size + ") is larger"
- + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT);
- if(size != -1) {
- if(size < LOWER_LIMIT_MAX_PACKET_SIZE) {
+ if (VDBG && (size > MAX_PACKET_SIZE_INT)) {
+ Log.w(TAG, "The packet size supported for the connection (" + size + ") is larger"
+ + " than the configured OBEX packet size: " + MAX_PACKET_SIZE_INT);
+ }
+ if (size != -1 && size < MAX_PACKET_SIZE_INT) {
+ if (size < LOWER_LIMIT_MAX_PACKET_SIZE) {
throw new IllegalArgumentException(size + " is less that the lower limit: "
+ LOWER_LIMIT_MAX_PACKET_SIZE);
}
diff --git a/obex/javax/obex/ObexTransport.java b/obex/javax/obex/ObexTransport.java
index a5a75f55f553..4cef0b33df4f 100644
--- a/obex/javax/obex/ObexTransport.java
+++ b/obex/javax/obex/ObexTransport.java
@@ -81,6 +81,8 @@ public interface ObexTransport {
* size. Therefore this value shall not change.
* For RFCOMM or other transport types where the OBEX packets size
* is unrelated to the transport packet size, return -1;
+ * Exception can be made (like PBAP transport) with a smaller value
+ * to avoid bad effect on other profiles using the RFCOMM;
* @return the maximum allowed OBEX packet that can be send over
* the transport. Or -1 in case of don't care.
*/
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml
new file mode 100644
index 000000000000..e0dfcf24700c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"বাতিল করুন"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml
new file mode 100644
index 000000000000..006301b2e94e
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Schließen"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
new file mode 100644
index 000000000000..1fe4c5c0c946
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-gu/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"છોડી દો"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml
new file mode 100644
index 000000000000..4bd44859ec8f
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"डिसमिस करा"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml
new file mode 100644
index 000000000000..15102541bb87
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"हटाउनुहोस्"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml
new file mode 100644
index 000000000000..36e7d3bdb216
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"ଖାରଜ କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
new file mode 100644
index 000000000000..22a6f59f091c
--- /dev/null
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-te/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"విస్మరించు"</string>
+</resources>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
index 7d9b4d78ce2a..6acd9ff07965 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -33,7 +33,7 @@
android:background="?android:attr/colorPrimary"
android:theme="@style/Theme.CollapsingToolbar.Settings">
- <com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout
+ <com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_one_line_height"
@@ -59,7 +59,7 @@
android:transitionName="shared_element_view"
app:layout_collapseMode="pin"/>
- </com.android.settingslib.collapsingtoolbar.AdjustableToolbarLayout>
+ </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
index 2a72a1ad65db..63d397c69353 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
@@ -17,6 +17,7 @@
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:textSize">20dp</item>
</style>
<style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java
deleted file mode 100644
index 0e7e595a3f04..000000000000
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/AdjustableToolbarLayout.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.settingslib.collapsingtoolbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.android.material.appbar.CollapsingToolbarLayout;
-
-/**
- * A customized version of CollapsingToolbarLayout that can apply different font size based on the
- * line count of its title.
- */
-public class AdjustableToolbarLayout extends CollapsingToolbarLayout {
-
- private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
-
- public AdjustableToolbarLayout(@NonNull Context context) {
- this(context, null);
-
- }
-
- public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public AdjustableToolbarLayout(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initCollapsingToolbar();
- }
-
- @SuppressWarnings("RestrictTo")
- private void initCollapsingToolbar() {
- this.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- v.removeOnLayoutChangeListener(this);
- final int count = getLineCount();
- if (count > TOOLBAR_MAX_LINE_NUMBER) {
- final ViewGroup.LayoutParams lp = getLayoutParams();
- lp.height = getResources()
- .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
- setScrimVisibleHeightTrigger(
- getResources().getDimensionPixelSize(
- R.dimen.scrim_visible_height_trigger_three_lines));
- setLayoutParams(lp);
- } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
- final ViewGroup.LayoutParams lp = getLayoutParams();
- lp.height = getResources()
- .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
- setScrimVisibleHeightTrigger(
- getResources().getDimensionPixelSize(
- R.dimen.scrim_visible_height_trigger_two_lines));
- setLayoutParams(lp);
- }
- }
- });
- }
-}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
index 4ae120ae286d..dbcecf1fe5b9 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseActivity.java
@@ -35,10 +35,18 @@ import com.google.android.material.resources.TextAppearanceConfig;
* A base Activity that has a collapsing toolbar layout is used for the activities intending to
* enable the collapsing toolbar function.
*/
-public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
+public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity implements
+ AppBarLayout.OnOffsetChangedListener {
+ private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
+ private static final int FULLY_EXPANDED_OFFSET = 0;
+ private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";
+
+ @Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @Nullable
private AppBarLayout mAppBarLayout;
+ private boolean mIsToolbarCollapsed;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -48,6 +56,12 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
super.setContentView(R.layout.collapsing_toolbar_base_layout);
mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
mAppBarLayout = findViewById(R.id.app_bar);
+ mAppBarLayout.addOnOffsetChangedListener(this);
+ if (savedInstanceState != null) {
+ mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
+ }
+
+ initCollapsingToolbar();
disableCollapsingToolbarLayoutScrollingBehavior();
final Toolbar toolbar = findViewById(R.id.action_bar);
@@ -107,14 +121,43 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
return true;
}
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
+ if (offset == FULLY_EXPANDED_OFFSET) {
+ mIsToolbarCollapsed = false;
+ } else {
+ mIsToolbarCollapsed = true;
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (isChangingConfigurations()) {
+ outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
+ }
+ }
+
/**
* Returns an instance of collapsing toolbar.
*/
+ @Nullable
public CollapsingToolbarLayout getCollapsingToolbarLayout() {
return mCollapsingToolbarLayout;
}
+ /**
+ * Return an instance of app bar.
+ */
+ @Nullable
+ public AppBarLayout getAppBarLayout() {
+ return mAppBarLayout;
+ }
+
private void disableCollapsingToolbarLayoutScrollingBehavior() {
+ if (mAppBarLayout == null) {
+ return;
+ }
final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
@@ -127,4 +170,39 @@ public class CollapsingToolbarBaseActivity extends SettingsTransitionActivity {
});
params.setBehavior(behavior);
}
+
+ @SuppressWarnings("RestrictTo")
+ private void initCollapsingToolbar() {
+ if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
+ return;
+ }
+ mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ v.removeOnLayoutChangeListener(this);
+ if (mIsToolbarCollapsed) {
+ return;
+ }
+ final int count = mCollapsingToolbarLayout.getLineCount();
+ if (count > TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_three_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_two_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ }
+ }
+ });
+ }
}
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
index c4c74ffc719b..faa73ff52d56 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/CollapsingToolbarBaseFragment.java
@@ -25,21 +25,31 @@ import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;
+import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.appbar.CollapsingToolbarLayout;
/**
* A base fragment that has a collapsing toolbar layout for enabling the collapsing toolbar design.
*/
-public abstract class CollapsingToolbarBaseFragment extends Fragment {
+public abstract class CollapsingToolbarBaseFragment extends Fragment implements
+ AppBarLayout.OnOffsetChangedListener {
+
+ private static final int TOOLBAR_MAX_LINE_NUMBER = 2;
+ private static final int FULLY_EXPANDED_OFFSET = 0;
+ private static final String KEY_IS_TOOLBAR_COLLAPSED = "is_toolbar_collapsed";
@Nullable
private CollapsingToolbarLayout mCollapsingToolbarLayout;
+ @Nullable
+ private AppBarLayout mAppBarLayout;
@NonNull
private Toolbar mToolbar;
@NonNull
private FrameLayout mContentFrameLayout;
+ private boolean mIsToolbarCollapsed;
@Nullable
@Override
@@ -48,6 +58,13 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
final View view = inflater.inflate(R.layout.collapsing_toolbar_base_layout, container,
false);
mCollapsingToolbarLayout = view.findViewById(R.id.collapsing_toolbar);
+ mAppBarLayout = view.findViewById(R.id.app_bar);
+ mAppBarLayout.addOnOffsetChangedListener(this);
+ if (savedInstanceState != null) {
+ mIsToolbarCollapsed = savedInstanceState.getBoolean(KEY_IS_TOOLBAR_COLLAPSED);
+ }
+ initCollapsingToolbar();
+ disableCollapsingToolbarLayoutScrollingBehavior();
mToolbar = view.findViewById(R.id.action_bar);
mContentFrameLayout = view.findViewById(R.id.content_frame);
return view;
@@ -60,6 +77,31 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
requireActivity().setActionBar(mToolbar);
}
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (getActivity().isChangingConfigurations()) {
+ outState.putBoolean(KEY_IS_TOOLBAR_COLLAPSED, mIsToolbarCollapsed);
+ }
+ }
+
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
+ if (offset == FULLY_EXPANDED_OFFSET) {
+ mIsToolbarCollapsed = false;
+ } else {
+ mIsToolbarCollapsed = true;
+ }
+ }
+
+ /**
+ * Return an instance of app bar.
+ */
+ @Nullable
+ public AppBarLayout getAppBarLayout() {
+ return mAppBarLayout;
+ }
+
/**
* Return the collapsing toolbar layout.
*/
@@ -75,4 +117,56 @@ public abstract class CollapsingToolbarBaseFragment extends Fragment {
public FrameLayout getContentFrameLayout() {
return mContentFrameLayout;
}
+
+ private void disableCollapsingToolbarLayoutScrollingBehavior() {
+ if (mAppBarLayout == null) {
+ return;
+ }
+ final CoordinatorLayout.LayoutParams params =
+ (CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();
+ final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();
+ behavior.setDragCallback(
+ new AppBarLayout.Behavior.DragCallback() {
+ @Override
+ public boolean canDrag(@NonNull AppBarLayout appBarLayout) {
+ return false;
+ }
+ });
+ params.setBehavior(behavior);
+ }
+
+ @SuppressWarnings("RestrictTo")
+ private void initCollapsingToolbar() {
+ if (mCollapsingToolbarLayout == null || mAppBarLayout == null) {
+ return;
+ }
+ mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ v.removeOnLayoutChangeListener(this);
+ if (mIsToolbarCollapsed) {
+ return;
+ }
+ final int count = mCollapsingToolbarLayout.getLineCount();
+ if (count > TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_three_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_three_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ } else if (count == TOOLBAR_MAX_LINE_NUMBER) {
+ final ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams();
+ lp.height = getResources()
+ .getDimensionPixelSize(R.dimen.toolbar_two_lines_height);
+ mCollapsingToolbarLayout.setScrimVisibleHeightTrigger(
+ getResources().getDimensionPixelSize(
+ R.dimen.scrim_visible_height_trigger_two_lines));
+ mCollapsingToolbarLayout.setLayoutParams(lp);
+ }
+ }
+ });
+ }
}
diff --git a/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml
new file mode 100644
index 000000000000..c58142d72618
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-bn/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"আরও জানুন"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-de/strings.xml b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml
new file mode 100644
index 000000000000..fe885aa6f091
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-de/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"Weitere Informationen"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml
new file mode 100644
index 000000000000..45387200bdc8
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-mr/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"अधिक जाणून घ्या"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml
new file mode 100644
index 000000000000..ecfec36337ee
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-ne/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"थप जान्नुहोस्"</string>
+</resources>
diff --git a/packages/SettingsLib/FooterPreference/res/values-or/strings.xml b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml
new file mode 100644
index 000000000000..e7924d646861
--- /dev/null
+++ b/packages/SettingsLib/FooterPreference/res/values-or/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="settingslib_learn_more_text" msgid="7385478101223578464">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
+</resources>
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
index 304c3439a60d..d993e4465343 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/SettingsSpinnerPreference.java
@@ -22,6 +22,7 @@ import android.view.View;
import android.widget.AdapterView;
import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.widget.settingsspinner.SettingsSpinner;
@@ -31,12 +32,12 @@ import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;
* This preference uses SettingsSpinner & SettingsSpinnerAdapter which provide default layouts for
* both view and drop down view of the Spinner.
*/
-public class SettingsSpinnerPreference extends Preference {
+public class SettingsSpinnerPreference extends Preference implements OnPreferenceClickListener {
private SettingsSpinnerAdapter mAdapter;
private AdapterView.OnItemSelectedListener mListener;
- private int mPosition; //Default 0 for internal shard storage.
- private boolean mIsClickable = true;
+ private int mPosition;
+ private boolean mShouldPerformClick;
/**
* Perform inflation from XML and apply a class-specific base style.
@@ -51,7 +52,7 @@ public class SettingsSpinnerPreference extends Preference {
public SettingsSpinnerPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setLayoutResource(R.layout.settings_spinner_preference);
- setSelectable(false);
+ setOnPreferenceClickListener(this);
}
/**
@@ -64,7 +65,7 @@ public class SettingsSpinnerPreference extends Preference {
public SettingsSpinnerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.settings_spinner_preference);
- setSelectable(false);
+ setOnPreferenceClickListener(this);
}
/**
@@ -76,6 +77,13 @@ public class SettingsSpinnerPreference extends Preference {
this(context, null);
}
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ mShouldPerformClick = true;
+ notifyChanged();
+ return true;
+ }
+
/** Sets adapter of the spinner. */
public <T extends SettingsSpinnerAdapter> void setAdapter(T adapter) {
mAdapter = adapter;
@@ -101,24 +109,19 @@ public class SettingsSpinnerPreference extends Preference {
notifyChanged();
}
- /** Set clickable of the spinner. */
- public void setClickable(boolean isClickable) {
- if (mIsClickable == isClickable) {
- return;
- }
- mIsClickable = isClickable;
- notifyChanged();
- }
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final SettingsSpinner spinner = (SettingsSpinner) holder.findViewById(R.id.spinner);
- spinner.setEnabled(mIsClickable);
- spinner.setClickable(mIsClickable);
spinner.setAdapter(mAdapter);
spinner.setSelection(mPosition);
spinner.setOnItemSelectedListener(mOnSelectedListener);
+ if (mShouldPerformClick) {
+ mShouldPerformClick = false;
+ // To show dropdown view.
+ spinner.performClick();
+ }
}
private final AdapterView.OnItemSelectedListener mOnSelectedListener =
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 9610c9443184..46f1e030af23 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -25,6 +25,7 @@
<style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:switchMinWidth">52dp</item>
+ <item name="android:minHeight">@dimen/settingslib_preferred_minimum_touch_target</item>
<item name="android:track">@drawable/settingslib_switch_track</item>
<item name="android:thumb">@drawable/settingslib_switch_thumb</item>
</style>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 89bb9e8bfe01..fa3f34c96ad2 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Bynaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Voeg gas by"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Verwyder gas"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Stel gassessie terug"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gas"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Neem \'n foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kies \'n prent"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index bc1bd1633e4c..7b4c832fd1d0 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ቅጽል ስም"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"እንግዳን አክል"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"እንግዳን አስወግድ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"እንግዳን ዳግም አስጀምር"</string>
<string name="guest_nickname" msgid="6332276931583337261">"እንግዳ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ፎቶ አንሳ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ምስል ይምረጡ"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f04aaac87b6d..611f2c44f565 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"উপনাম"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"অতিথি যোগ কৰক"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"অতিথি আঁতৰাওক"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"অতিথিৰ ছেশ্বন ৰিছেট কৰক"</string>
<string name="guest_nickname" msgid="6332276931583337261">"অতিথি"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"এখন ফট’ তোলক"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"এখন প্ৰতিচ্ছবি বাছনি কৰক"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index b7cf11ae3754..c50a22d18605 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Ləqəb"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Qonaq əlavə edin"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Qonağı silin"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Qonaq sessiyasını sıfırlayın"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Qonaq"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto çəkin"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Şəkil seçin"</string>
@@ -576,7 +575,7 @@
<string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string>
<string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string>
<string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string>
- <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string>
+ <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Naqilli qulaqlıq"</string>
<string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Aktiv"</string>
<string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Deaktiv"</string>
<string name="carrier_network_change_mode" msgid="4257621815706644026">"Operator şəbəkəsinin dəyişilməsi"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 97c281ad2d67..e26d0650c8cc 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesiju gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Slikaj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 09e584318173..7899fa687ddc 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавяне на гост"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Премахване на госта"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Нулиране на сесията като гост"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Правене на снимка"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Избиране на изображение"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 88abe33d1f18..9eb20f90735f 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ukloni gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi sesiju gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Snimite fotografiju"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberite sliku"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index f499ab6cc7c0..d3590bf9e8d2 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Àlies"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Afegeix un convidat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Suprimeix el convidat"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restableix el convidat"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fes una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Tria una imatge"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 4d07eff0e858..5c664b987101 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Přezdívka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Přidat hosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranit hosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetovat hosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Host"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pořídit fotku"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrat obrázek"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 98f53011d2ca..59bfab8ddea8 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Ψευδώνυμο"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Προσθήκη επισκέπτη"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Κατάργηση επισκέπτη"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Επαναφορά περιόδου επισκέπτη"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Επισκέπτης"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Λήψη φωτογραφίας"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Επιλογή εικόνας"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 6ff48541e4e8..26c7b2c7a760 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apodo"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Añadir invitado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar invitado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer invitado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Hacer foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Seleccionar una imagen"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index ef7b7db2bb9b..194aeaff4b15 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Hüüdnimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisa külaline"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Eemalda külaline"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Lähtesta külastajaseanss"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Külaline"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Pildistage"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valige pilt"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 93506105d964..33e2314dd887 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -528,7 +528,7 @@
<string name="media_transfer_wired_device_name" msgid="4447880899964056007">"Audio-gailu kableduna"</string>
<string name="help_label" msgid="3528360748637781274">"Laguntza eta iritziak"</string>
<string name="storage_category" msgid="2287342585424631813">"Biltegiratzea"</string>
- <string name="shared_data_title" msgid="1017034836800864953">"Partekatutako datuak"</string>
+ <string name="shared_data_title" msgid="1017034836800864953">"Datu partekatuak"</string>
<string name="shared_data_summary" msgid="5516326713822885652">"Ikusi eta aldatu partekatutako datuak"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Ez dago erabiltzaile honen datu partekaturik."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"Errore bat gertatu da datu partekatuak eskuratzean. Saiatu berriro."</string>
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Goitizena"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gehitu gonbidatua"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Kendu gonbidatua"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Berrezarri gonbidatuentzako saioa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gonbidatua"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Atera argazki bat"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Aukeratu irudi bat"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 964162b34357..a11a00a5f65d 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Lempinimi"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lisää vieras"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Poista vieras"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Nollaa vieras"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vieras"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ota kuva"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Valitse kuva"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 73f98ec23ccf..dba912ea3920 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Alcume"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engadir convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Quitar convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Restablecer sesión de convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escoller imaxe"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 5620d946b999..bc74092efa8d 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"प्रचलित नाम"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"मेहमान जोड़ें"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"मेहमान हटाएं"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करें"</string>
<string name="guest_nickname" msgid="6332276931583337261">"मेहमान"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फ़ोटो खींचें"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"कोई इमेज चुनें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 0ff35f890407..d18d34cb0037 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nadimak"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodavanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Uklanjanje gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Poništi gostujuću sesiju"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiraj"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Odaberi sliku"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9bd4d1263abd..3ad3590ca728 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Becenév"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Vendég hozzáadása"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Vendég munkamenet eltávolítása"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Vendég munkamenet visszaállítása"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Vendég"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotó készítése"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Kép kiválasztása"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 662a67361b33..da92e7d4517f 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Gælunafn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Bæta gesti við"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjarlægja gest"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Endurstilla gestastillingu"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gestur"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Taka mynd"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velja mynd"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 2c2d11fecda4..6f7565e3fb02 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Aggiungi ospite"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Rimuovi ospite"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Reimposta sessione Ospite"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Ospite"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Scatta una foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Scegli un\'immagine"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index ddae3c72babb..70dd9e74929b 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Лақап ат"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Қонақ қосу"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Қонақты жою"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Қонақ сеансын әдепкі күйге қайтару"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Қонақ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотосуретке түсіру"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Сурет таңдау"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d970e9590c36..26595f5cc067 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ឈ្មោះ​ហៅក្រៅ"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"បញ្ចូល​ភ្ញៀវ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ដកភ្ញៀវចេញ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"កំណត់​ភ្ញៀវឡើង​វិញ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ភ្ញៀវ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ថតរូប"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ជ្រើសរើស​រូបភាព"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 8bad32006594..b36ef8d2a2da 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ಅಡ್ಡ ಹೆಸರು"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ಅತಿಥಿಯನ್ನು ಸೇರಿಸಿ"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕಿ"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ಅತಿಥಿ"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ಫೋಟೋ ತೆಗೆದುಕೊಳ್ಳಿ"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ಚಿತ್ರವನ್ನು ಆರಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 3383602753f1..ad0ad1fb28bf 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Slapyvardis"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridėti svečią"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Pašalinti svečią"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Iš naujo nustatyti svečią"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Svečias"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografuoti"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pasirinkti vaizdą"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index d655afc7ae35..586de6fcfdf7 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Segvārds"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pievienot viesi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Noņemt viesi"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Atiestatīt viesa sesiju"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Viesis"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Uzņemt fotoattēlu"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izvēlēties attēlu"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index bd7f074f01a0..0d0f345af7c3 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Прекар"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додајте гостин"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Отстрани гостин"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетирајте го гостинот"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гостин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Фотографирајте"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одберете слика"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 1e80ccd0f3ab..655be1a74c31 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"വിളിപ്പേര്"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"അതിഥിയെ ചേർക്കുക"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"അതിഥിയെ നീക്കം ചെയ്യുക"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"അതിഥിയെ റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_nickname" msgid="6332276931583337261">"അതിഥി"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ഒരു ഫോട്ടോ എടുക്കുക"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ഒരു ചിത്രം തിരഞ്ഞെടുക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 40b65efe275e..07ed369b8d36 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Хоч"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Зочин нэмэх"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Зочин хасах"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Зочныг шинэчлэх"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Зочин"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зураг авах"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Зураг сонгох"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 6a46edee6ce5..fe8e8375a65a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"टोपणनाव"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"अतिथी जोडा"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"अतिथी काढून टाका"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"अतिथी सेशन रीसेट करा"</string>
<string name="guest_nickname" msgid="6332276931583337261">"अतिथी"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"फोटो काढा"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"इमेज निवडा"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7156a8ef6548..b383ad84cadb 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"နာမည်ပြောင်"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"ဧည့်သည့် ထည့်ရန်"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"ဧည့်သည်ကို ဖယ်ထုတ်ရန်"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်ရန်"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ဧည့်သည်"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ဓာတ်ပုံရိုက်ရန်"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"ပုံရွေးရန်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index bb93a29feaa5..84c231faed46 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Kallenavn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Legg til en gjest"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Fjern gjesten"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Tilbakestill gjest"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gjest"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta et bilde"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Velg et bilde"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index a33bbf3e2dd9..1837eabf2370 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Bijnaam"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Gast toevoegen"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Gast verwijderen"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Gastsessie resetten"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gast"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Foto maken"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Afbeelding kiezen"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 5f410a86691b..bd77d881560f 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodaj gościa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Usuń gościa"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetuj sesję gościa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gość"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Zrób zdjęcie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Wybierz obraz"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3c8d928a7213..e39b58bb8344 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index fc98aa732606..a5c0d1d58d40 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Alcunha"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Repor convidado"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3c8d928a7213..e39b58bb8344 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Apelido"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adicionar convidado"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Remover convidado"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Redefinir sessão de visitante"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Convidado"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Tirar uma foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Escolher uma imagem"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 4db2f315a452..e1b0390fbace 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Resetați sesiunea pentru invitați"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Invitat"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Faceți o fotografie"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 0bcdc230c089..1e5fce5f3bc9 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдоним"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Добавить гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Удалить аккаунт гостя"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Сбросить гостевой сеанс"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гость"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сделать снимок"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Выбрать фото"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index ef12ad36c5e1..09c0bf993f34 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Prezývka"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Pridať hosťa"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odobrať hosťa"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Obnoviť reláciu hosťa"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Hosť"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Odfotiť"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Vybrať obrázok"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cbdfefcd424a..b698c19ff8b8 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Vzdevek"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Dodajanje gosta"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Odstranitev gosta"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ponastavi gosta"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gost"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Fotografiranje"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Izberi sliko"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 3859be937d47..b3c23b667a42 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -567,8 +567,7 @@
<string name="user_nickname" msgid="262624187455825083">"Надимак"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додај госта"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Уклони госта"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Ресетуј сесију госта"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гост"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Сликај"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Одабери слику"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7dcca0d2b611..124c063bea95 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Smeknamn"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Lägg till gäst"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Ta bort gäst"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Återställ gästsession"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Gäst"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Ta ett foto"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Välj en bild"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b7aff721c405..7f67b88aa837 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -452,7 +452,7 @@
<string name="power_remaining_duration_shutdown_imminent" product="tablet" msgid="7703677921000858479">"แท็บเล็ตอาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_remaining_duration_shutdown_imminent" product="device" msgid="4374784375644214578">"อุปกรณ์อาจปิดเครื่องในไม่ช้า (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
<string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
- <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g> จึงจะเต็ม"</string>
+ <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string>
<string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string>
<string name="power_charging_limited" msgid="7956120998372505295">"<xliff:g id="LEVEL">%1$s</xliff:g> - จำกัดการชาร์จชั่วคราว"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"ชื่อเล่น"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"เพิ่มผู้ใช้ชั่วคราว"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"นำผู้ใช้ชั่วคราวออก"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"รีเซ็ตผู้เข้าร่วม"</string>
<string name="guest_nickname" msgid="6332276931583337261">"ผู้ใช้ชั่วคราว"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"ถ่ายรูป"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"เลือกรูปภาพ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 6d1f6abbdf96..cc7db29f3d32 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nickname"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Magdagdag ng bisita"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Alisin ang bisita"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"I-reset ang bisita"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Bisita"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Kumuha ng larawan"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Pumili ng larawan"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 82e481bd0613..2cb10763fcc9 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -568,8 +568,7 @@
<string name="user_nickname" msgid="262624187455825083">"Псевдонім"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Додати гостя"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Видалити гостя"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Скинути сеанс у режимі \"Гість\""</string>
<string name="guest_nickname" msgid="6332276931583337261">"Гість"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Зробити фотографію"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Вибрати зображення"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 7f4e30aa33c4..3e11124597d9 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Nik"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Mehmon kiritish"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Mehmonni olib tashlash"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Mehmon seansini tiklash"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Mehmon"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Suratga olish"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Rasm tanlash"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 2fe791a5a47c..0fa97e2011ce 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -566,8 +566,7 @@
<string name="user_nickname" msgid="262624187455825083">"Isiteketiso"</string>
<string name="guest_new_guest" msgid="3482026122932643557">"Engeza isivakashi"</string>
<string name="guest_exit_guest" msgid="5908239569510734136">"Susa isihambeli"</string>
- <!-- no translation found for guest_reset_guest (6110013010356013758) -->
- <skip />
+ <string name="guest_reset_guest" msgid="6110013010356013758">"Setha kabusha isivakashi"</string>
<string name="guest_nickname" msgid="6332276931583337261">"Isihambeli"</string>
<string name="user_image_take_photo" msgid="467512954561638530">"Thatha isithombe"</string>
<string name="user_image_choose_photo" msgid="1363820919146782908">"Khetha isithombe"</string>
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
index b0c5314a2ec0..53a382a9ebf6 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/SettingsSpinnerPreferenceTest.java
@@ -89,24 +89,4 @@ public class SettingsSpinnerPreferenceTest {
assertThat(mSpinnerPreference.getSelectedItem())
.isEqualTo(mSpinner.getAdapter().getItem(1));
}
-
- @Test
- public void onBindViewHolder_setClickableTrue_isClickableTrue() {
- mSpinnerPreference.setClickable(true);
-
- mSpinnerPreference.onBindViewHolder(mViewHolder);
-
- assertThat(mSpinner.isClickable()).isTrue();
- assertThat(mSpinner.isEnabled()).isTrue();
- }
-
- @Test
- public void onBindViewHolder_setClickableFalse_isClickableFalse() {
- mSpinnerPreference.setClickable(false);
-
- mSpinnerPreference.onBindViewHolder(mViewHolder);
-
- assertThat(mSpinner.isClickable()).isFalse();
- assertThat(mSpinner.isEnabled()).isFalse();
- }
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8c092ae37222..604310a9e905 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -454,6 +454,14 @@
android:finishOnCloseSystemDialogs="true">
</activity>
+ <!-- started from SensoryPrivacyService -->
+ <activity android:name=".sensorprivacy.television.TvUnblockSensorActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_SENSOR_PRIVACY"
+ android:theme="@style/BottomSheet"
+ android:finishOnCloseSystemDialogs="true">
+ </activity>
+
<!-- started from UsbDeviceSettingsManager -->
<activity android:name=".usb.UsbAccessoryUriActivity"
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 149b31323ab3..0a036c811867 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -85,7 +85,7 @@
<string name="kg_login_too_many_attempts" msgid="4519957179182578690">"‏تلاش‎های زیادی برای کشیدن الگو صورت گرفته است"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"پین خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"گذرواژه خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. \n\nلطفاً پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"کد پین سیم‌کارت اشتباه است، اکنون برای باز کردن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
<item quantity="one">کد پین سیم‌کارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر می‌توانید تلاش کنید.</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index af43cf7a293f..a41cce7b74bf 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -38,7 +38,7 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ઝડપથી ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ધીમેથી ચાર્જિંગ"</string>
- <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ હંગામી રૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
+ <string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ હંગામીરૂપે પ્રતિબંધિત કરવામાં આવ્યું છે"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"તમારું ચાર્જર કનેક્ટ કરો."</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index b307544f5e3c..0692aeff0e0e 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -36,7 +36,7 @@
<string name="keyguard_charged" msgid="5478247181205188995">"चार्ज भयो"</string>
<string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तारविनै चार्ज गर्दै"</string>
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज गरिँदै"</string>
- <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै"</string>
+ <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • मन्द गतिमा चार्ज गरिँदै"</string>
<string name="keyguard_plugged_in_charging_limited" msgid="6091488837901216962">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिङ केही समयका लागि सीमित पारिएको छ"</string>
<string name="keyguard_low_battery" msgid="1868012396800230904">"तपाईंको चार्जर जोड्नुहोस्।"</string>
diff --git a/packages/SystemUI/res-product/values-fa/strings.xml b/packages/SystemUI/res-product/values-fa/strings.xml
index 52fa2d85d074..cd98ef60994d 100644
--- a/packages/SystemUI/res-product/values-fa/strings.xml
+++ b/packages/SystemUI/res-product/values-fa/strings.xml
@@ -38,8 +38,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"<xliff:g id="NUMBER_0">%1$d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق دیگر، نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشته‌اید. نمایه کاری پاک می‌شود که با آن همه داده‌های نمایه حذف می‌شود."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‏شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. بعد از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"شما الگوی باز کردن قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌شود که با استفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‏الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. بعداز <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌‎شود که بااستفاده از یک حساب ایمیل قفل رایانه لوحی‌تان را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"الگوی بازگشایی قفل را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیده‌اید. پس‌از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته می‌شود که بااستفاده از یک حساب ایمیل قفل تلفن را باز کنید.\n\n لطفاً پس‌از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="global_action_lock_message" product="default" msgid="7092460751050168771">"برای گزینه‌های بیشتر، قفل تلفن را باز کنید"</string>
<string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"برای گزینه‌های بیشتر، قفل رایانه لوحی را باز کنید"</string>
<string name="global_action_lock_message" product="device" msgid="3165224897120346096">"برای گزینه‌های بیشتر، قفل دستگاه را باز کنید"</string>
diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml
new file mode 100644
index 000000000000..fc3b4ed6eecb
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_button_state_list_animator.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="1.0"
+ android:valueTo="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="1.0"
+ android:valueTo="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+ <item android:state_focused="false">
+ <set>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleX"
+ android:valueFrom="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:duration="200"
+ android:propertyName="scaleY"
+ android:valueFrom="@dimen/bottom_sheet_button_selection_scaled"
+ android:valueTo="1.0"
+ android:valueType="floatType"/>
+ </set>
+ </item>
+</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml
new file mode 100644
index 000000000000..cace36d68b43
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_enter.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_quint">
+ <translate android:fromYDelta="100%"
+ android:toYDelta="0"
+ android:duration="900"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml
new file mode 100644
index 000000000000..f7efe7cd2584
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_bottom_sheet_exit.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@android:interpolator/decelerate_quint">
+ <translate android:fromYDelta="0"
+ android:toYDelta="100%"
+ android:duration="500"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml b/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml
new file mode 100644
index 000000000000..e6ceeb919232
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_collapse.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="height"
+ android:valueTo="@dimen/privacy_chip_dot_size"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="marginEnd"
+ android:valueTo="@dimen/privacy_chip_dot_margin_horizontal"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="radius"
+ android:valueTo="@dimen/privacy_chip_dot_radius"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml b/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml
new file mode 100644
index 000000000000..4a510ae6cab8
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_expand.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_expand_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="height"
+ android:valueTo="@dimen/privacy_chip_height"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="marginEnd"
+ android:valueTo="0"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="radius"
+ android:valueTo="@dimen/privacy_chip_radius"
+ android:valueType="floatType"/>
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml b/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml
new file mode 100644
index 000000000000..701489a28450
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_fade_in.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="255"
+ android:valueType="intType"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml b/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml
new file mode 100644
index 000000000000..fa134717ba6e
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_privacy_chip_fade_out.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:ordering="together"
+ android:interpolator="@interpolator/tv_privacy_chip_collapse_interpolator"
+ android:duration="@integer/privacy_chip_animation_millis">
+ <objectAnimator
+ android:propertyName="dotAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+ <objectAnimator
+ android:propertyName="bgAlpha"
+ android:valueTo="0"
+ android:valueType="intType"/>
+</set> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml b/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml
new file mode 100644
index 000000000000..9b0bae09b326
--- /dev/null
+++ b/packages/SystemUI/res/color/bottom_sheet_button_background_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:color="@color/bottom_sheet_button_background_color_focused"/>
+ <item android:color="@color/bottom_sheet_button_background_color_unfocused"/>
+</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml b/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml
new file mode 100644
index 000000000000..05248f17097b
--- /dev/null
+++ b/packages/SystemUI/res/color/bottom_sheet_button_text_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true"
+ android:color="@color/bottom_sheet_button_text_color_focused"/>
+ <item android:color="@color/bottom_sheet_button_text_color_unfocused"/>
+</selector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml b/packages/SystemUI/res/drawable/bottom_sheet_background.xml
index 93f8724b22a9..87850a0d00ec 100644
--- a/packages/SystemUI/res/drawable/tv_rect_shadow_rounded.xml
+++ b/packages/SystemUI/res/drawable/bottom_sheet_background.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,12 +14,7 @@
~ 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">
-
- <corners android:radius="20dp"/>
- <solid android:color="@color/tv_audio_recording_indicator_icon_background"/>
- <stroke android:width="1dp" android:color="@color/tv_audio_recording_indicator_stroke"/>
-
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <solid android:color="@color/bottom_sheet_background_color"/>
+ <corners android:radius="@dimen/bottom_sheet_corner_radius"/>
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml
new file mode 100644
index 000000000000..cd2aa9c751d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bottom_sheet_background_with_blur.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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">
+ <solid android:color="@color/bottom_sheet_background_color_with_blur"/>
+ <corners android:radius="@dimen/bottom_sheet_corner_radius"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml
new file mode 100644
index 000000000000..585a6bc771f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bottom_sheet_button_background.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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">
+ <solid android:color="@color/bottom_sheet_button_background_color"/>
+ <corners android:radius="@dimen/bottom_sheet_button_corner_radius"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml b/packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml
new file mode 100644
index 000000000000..429812484674
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/tv_privacy_chip_collapse_interpolator.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.4"
+ android:controlY1="1.00"
+ android:controlX2="0.12"
+ android:controlY2="1.00"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml b/packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml
new file mode 100644
index 000000000000..ed44715130e9
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/tv_privacy_chip_expand_interpolator.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:controlX1="0.12"
+ android:controlY1="1.00"
+ android:controlX2="0.4"
+ android:controlY2="1.00"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_output_list_item.xml b/packages/SystemUI/res/layout/media_output_list_item.xml
index b563633f24fe..16c03e124794 100644
--- a/packages/SystemUI/res/layout/media_output_list_item.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item.xml
@@ -81,6 +81,7 @@
android:visibility="gone"/>
<SeekBar
android:id="@+id/volume_seekbar"
+ style="@*android:style/Widget.DeviceDefault.SeekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"/>
diff --git a/packages/SystemUI/res/layout/tv_bottom_sheet.xml b/packages/SystemUI/res/layout/tv_bottom_sheet.xml
new file mode 100644
index 000000000000..b69cdc76ae40
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_bottom_sheet.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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:id="@+id/bottom_sheet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:minHeight="@dimen/bottom_sheet_min_height"
+ android:paddingHorizontal="@dimen/bottom_sheet_padding_horizontal"
+ android:paddingVertical="@dimen/bottom_sheet_padding_vertical">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="80dp"
+ android:gravity="center"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/bottom_sheet_icon"
+ android:layout_width="@dimen/bottom_sheet_icon_size"
+ android:layout_height="@dimen/bottom_sheet_icon_size"
+ android:layout_gravity="center_vertical"
+ android:tint="@color/bottom_sheet_icon_color"/>
+ <ImageView
+ android:id="@+id/bottom_sheet_second_icon"
+ android:layout_width="@dimen/bottom_sheet_icon_size"
+ android:layout_height="@dimen/bottom_sheet_icon_size"
+ android:layout_marginStart="@dimen/bottom_sheet_icon_margin"
+ android:layout_gravity="center_vertical"
+ android:tint="@color/bottom_sheet_icon_color"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/bottom_sheet_padding_horizontal"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <TextView
+ android:id="@+id/bottom_sheet_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/bottom_sheet_title_margin_bottom"
+ android:textAppearance="@style/BottomSheet.TitleText"/>
+
+ <TextView
+ android:id="@+id/bottom_sheet_body"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/bottom_sheet_details_margin_bottom"
+ android:textAppearance="@style/BottomSheet.BodyText" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="@dimen/bottom_sheet_actions_width"
+ android:layout_height="match_parent"
+ android:gravity="center">
+ <Button
+ android:id="@+id/bottom_sheet_positive_button"
+ style="@style/BottomSheet.ActionItem" />
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="@dimen/bottom_sheet_actions_spacing" />
+ <Button
+ android:id="@+id/bottom_sheet_negative_button"
+ style="@style/BottomSheet.ActionItem" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
index dff148b2c570..6218a5e6ea82 100644
--- a/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/tv_ongoing_privacy_chip.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -20,16 +20,25 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="12dp"
- android:layout_gravity="center">
+ android:gravity="center"
+ android:animateLayoutChanges="false"
+ android:padding="@dimen/privacy_chip_margin">
+
+ <ImageView
+ android:id="@+id/chip_drawable"
+ android:layout_width="51dp"
+ android:layout_height="@dimen/privacy_chip_height"
+ android:minWidth="@dimen/privacy_chip_dot_bg_width"
+ android:minHeight="@dimen/privacy_chip_dot_bg_height"
+ android:layout_gravity="top|end" />
<LinearLayout
android:id="@+id/icons_container"
- android:background="@drawable/tv_rect_shadow_rounded"
- android:padding="@dimen/privacy_chip_icon_padding"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal"/>
-
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical|end"
+ android:animateLayoutChanges="true"
+ android:paddingHorizontal="@dimen/privacy_chip_padding_horizontal" />
</FrameLayout>
diff --git a/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml b/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
new file mode 100644
index 000000000000..f22e8ef9d005
--- /dev/null
+++ b/packages/SystemUI/res/transition/tv_privacy_chip_collapse.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <fade android:fadingMode="fade_in" />
+ <changeBounds/>
+</transitionSet>
diff --git a/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml b/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
new file mode 100644
index 000000000000..059ebc84ea7e
--- /dev/null
+++ b/packages/SystemUI/res/transition/tv_privacy_chip_expand.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
+ <changeBounds/>
+ <fade android:fadingMode="fade_out" />
+</transitionSet>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4736adbfb62f..ae8de876bfeb 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ተጠቃሚ አክል"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"አዲስ ተጠቃሚ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"እንግዳ ይወገድ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"እንግዳ ዳግም ይጀምር?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"አስወግድ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ዳግም አስጀምር"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"እንኳን በደህና ተመለሱ እንግዳ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ክፍለ-ጊዜዎን መቀጠል ይፈልጋሉ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"እንደገና ጀምር"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b493d897fd22..2881a04fbb50 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -488,12 +488,10 @@
<string name="user_add_user" msgid="4336657383006913022">"إضافة مستخدم"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"مستخدم جديد"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"هل تريد إزالة جلسة الضيف؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"هل تريد إعادة ضبط جلسة الضيف؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"سيتم حذف كل التطبيقات والبيانات في هذه الجلسة."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"إزالة"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"إعادة الضبط"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مرحبًا بك مجددًا في جلسة الضيف"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"هل تريد متابعة جلستك؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"البدء من جديد"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c3b96a40023d..9502454d1c8c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1035,7 +1035,7 @@
<string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Tam ekranı böyüdün"</string>
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Ekran hissəsinin böyüdülməsi"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Dəyişdirici"</string>
- <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Əlçatımlılıq düyməsi əlçatımlılıq jestini əvəz etdi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
+ <string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Jest xüsusi imkanlar düyməsinə dəyişdirildi\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
<string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"Əlçatımlılıq jestindən düymə\n\n"<annotation id="link">"Ayarlarına"</annotation>" keçə bilərsiniz"</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürü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 fe89267456a9..345dcaa8d46f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite li da uklonite gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Želite li da resetujete sesiju gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetuj"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli nazad, goste!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li da nastavite sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni iz početka"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 2e98ad94383a..5afd979d34f5 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Дадаць карыстальніка"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Новы карыстальнік"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Выдаліць госця?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Скінуць гасцявы сеанс?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Выдаліць"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Скінуць"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"З вяртаннем, госць!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Хочаце працягнуць сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Пачаць зноў"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 9f71f43605ae..c035553e3e99 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ব্যবহারকারী জুড়ুন"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"নতুন ব্যবহারকারী"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"অতিথি সরাবেন?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"গেস্ট সেশন রিসেট করবেন?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"সরান"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"রিসেট করুন"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"অতিথি, আপনি ফিরে আসায় আপনাকে স্বাগত!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"আপনি কি আপনার সেশনটি চালিয়ে যেতে চান?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"আবার শুরু করুন"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"স্ক্রিনের কিছুটা অংশ বড় করুন"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"বদল করুন"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"অ্যাক্সেসিবিলিটি জেসচার পরিবর্তন করে অ্যাক্সেসেবিলিটি বোতাম করা হয়েছে\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"আপনি অ্যাক্সেসিবিলিটি জেসচারের বদলে \n\n"<annotation id="link">"সেটিংস"</annotation>" বোতামে সুইচ করতে পারেন"</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 17dbbe95a010..ae7ac13cf220 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti sesiju gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Poništi"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Zdravo! Lijepo je opet vidjeti goste."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2428d55fa1e6..14d391655791 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Afegeix un usuari"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuari nou"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vols suprimir el convidat?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vols restablir el convidat?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Suprimeix"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restableix"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvingut de nou, convidat."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vols continuar amb la sessió?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Torna a començar"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index d8e0a6a1d446..ae0f0f3836a2 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Přidat uživatele"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový uživatel"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstranit hosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Resetovat hosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstranit"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetovat"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Vítejte zpět v relaci hosta!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relaci pokračovat?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začít znovu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ca44f0a350d7..78a56cd7c9e9 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Tilføj bruger"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruger"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gæsten?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vil du nulstille gæsten?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nulstil"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbage, gæst!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsætte din session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start forfra"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 274ca3a32a2c..672ffd04188f 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Nutzer hinzufügen"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Neuer Nutzer"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast entfernen?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gastsitzung zurücksetzen?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Entfernen"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Zurücksetzen"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Willkommen zurück im Gastmodus"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Möchtest du deine Sitzung fortsetzen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Neu starten"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Teil des Bildschirms vergrößern"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Schalter"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"Die Schaltfläche „Bedienungshilfen“ ersetzt die Touch-Geste für Bedienungshilfen\n\n"<annotation id="link">"Einstellungen aufrufen"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"Du kannst von der barrierefreien Geste zu einer Schaltfläche wechseln\n\n"<annotation id="link">"Einstellungen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 7b135a3e32da..3662da203380 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Προσθήκη χρήστη"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Νέος χρήστης"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Κατάργηση επισκέπτη;"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Επαναφορά περιόδου επισκέπτη;"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Κατάργηση"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Επαναφορά"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Kαλώς ορίσατε ξανά!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Θέλετε να συνεχίσετε την περίοδο σύνδεσής σας;"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Έναρξη από την αρχή"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 0479ad0fcb85..13b76534dd90 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Agregar usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Usuario nuevo"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"¿Quieres restablecer el usuario?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"¡Hola de nuevo, invitado!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres retomar la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 65648153e8f9..171afee61822 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Añadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuevo usuario"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"¿Quitar invitado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"¿Restablecer invitado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hola de nuevo, invitado"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"¿Quieres continuar con la sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Volver a empezar"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 662282106d1d..497845707e46 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lisa kasutaja"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Uus kasutaja"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Kas eemaldada külaline?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Kas lähtestada külastajaseanss?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eemalda"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Lähtesta"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tere tulemast tagasi, külaline!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Kas soovite seansiga jätkata?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Alusta uuesti"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 6d8a8fdfad0c..40f39989c83b 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Gehitu erabiltzaile bat"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Erabiltzaile berria"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gonbidatua kendu nahi duzu?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gonbidatuentzako saioa berrezarri nahi duzu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kendu"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Berrezarri"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Ongi etorri berriro, gonbidatu hori!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Saioarekin jarraitu nahi duzu?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Hasi berriro"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ce3e676db760..f17fd4180718 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"افزودن کاربر"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"کاربر جدید"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مهمان حذف شود؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"جلسه مهمان بازنشانی شود؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامه‌ها و داده‌های این جلسه حذف خواهد شد."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"حذف"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"بازنشانی"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مهمان گرامی، بازگشتتان را خوش آمد می‌گوییم!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"آیا می‌خواهید جلسه‌تان را ادامه دهید؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"شروع مجدد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 90f47ef42a5a..3546ea0f02d3 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lisää käyttäjä"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Uusi käyttäjä"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Poistetaaanko vieras?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Nollataanko vieras?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Poista"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nollaa"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Tervetuloa takaisin!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Haluatko jatkaa istuntoa?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Aloita alusta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 030428034545..39d564fbcbfb 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Réinitialiser la session Invité?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Réinitialiser"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recommencer"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index c4022611f897..4f0670161a1a 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ajouter un utilisateur"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nouvel utilisateur"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Supprimer l\'invité ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Réinitialiser la session Invité ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Supprimer"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Réinitialiser"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bienvenue à nouveau dans la session Invité"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Voulez-vous poursuivre la dernière session ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Non, nouvelle session"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e7b3e925d5e2..0641cef02334 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Engadir usuario"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuario"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Queres quitar o convidado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Queres restablecer a sesión de convidado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Quitar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Restablecer"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Benvido de novo, convidado"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Queres continuar coa túa sesión?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Comezar de novo"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index a99558e4d84e..25caa5347e85 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -1036,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"સ્ક્રીનનો કોઈ ભાગ મોટો કરો"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"સ્વિચ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ઍક્સેસિબિલિટી સંકેતને ઍક્સેસિબિલિટી બટન વડે બદલવામાં આવ્યા છે\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"તમે ઍક્સેસિબિલિટી સંકેત પરથી કોઈ બટન પર સ્વિચ કરી શકો છો\n\n"<annotation id="link">"સેટિંગ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 4196b1f41d86..3d65fa44d61f 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"उपयोगकर्ता जोड़ें"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नया उपयोगकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"क्या आप मेहमान को हटाना चाहते हैं?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"क्या आप मेहमान के तौर पर ब्राउज़ करने का सेशन रीसेट करना चाहते हैं?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सत्र के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"निकालें"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रीसेट करें"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"मेहमान, आपका फिर से स्वागत है!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"क्‍या आप अपना सत्र जारी रखना चाहते हैं?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"फिर से शुरू करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 6f7aee23f190..abbbae7985d4 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodavanje korisnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novi korisnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ukloniti gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Poništiti gostujuću sesiju?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji bit će izbrisani."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ukloni"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Poništi"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Dobro došli natrag, gostu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite li nastaviti sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Počni ispočetka"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 800c9dc36a07..15106bb4c157 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Felhasználó hozzáadása"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Új felhasználó"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Eltávolítja a vendég munkamenetet?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Visszaállítja a vendég munkamenetet?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Eltávolítás"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Visszaállítás"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Örülünk, hogy visszatért, vendég!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Folytatja a munkamenetet?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Újrakezdés"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index deeeb209e1e3..2e2141ee075c 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ավելացնել օգտատեր"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Նոր օգտատեր"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Հեռացնե՞լ հյուրին"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Վերակայե՞լ հյուրի աշխատաշրջանը"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր ծրագրերն ու տվյալները կջնջվեն:"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Հեռացնել"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Վերակայել"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Բարի վերադարձ, հյուր"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Շարունակե՞լ աշխատաշրջանը։"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Վերսկսել"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index a6cb798a188e..53a3165776fd 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Tambahkan pengguna"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baru"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Hapus tamu?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Reset sesi tamu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua aplikasi dan data di sesi ini akan dihapus."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hapus"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Reset"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat datang kembali, tamu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Lanjutkan sesi Anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulai ulang"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 01bad1c1ce90..151564aee0d4 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Bæta notanda við"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nýr notandi"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Fjarlægja gest?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Endurstilla gestastillingu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjarlægja"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Endurstilla"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkominn aftur, gestur!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Viltu halda áfram með lotuna?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Byrja upp á nýtt"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 066cd9344e91..454b5bba4a49 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Aggiungi utente"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nuovo utente"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Rimuovere l\'ospite?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Reimpostare sessione Ospite?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tutte le app e i dati di questa sessione verranno eliminati."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Rimuovi"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Reimposta"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Ti ridiamo il benvenuto alla sessione Ospite."</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vuoi continuare la sessione?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Ricomincia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index b2f0fd259702..3dedff995e0e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"הוספת משתמש"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"משתמש חדש"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"להסיר אורח?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"לאפס את הגלישה כאורח?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"כל האפליקציות והנתונים בסשן הזה יימחקו."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"הסרה"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"איפוס"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"שמחים לראותך שוב!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"האם ברצונך להמשיך בפעילות באתר?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"סשן חדש"</string>
@@ -725,7 +723,7 @@
<string name="notification_channel_unsilenced" msgid="94878840742161152">"ההודעות אלה יישלחו כהתראות"</string>
<string name="inline_blocking_helper" msgid="2891486013649543452">"ההתראות האלה בדרך כלל נדחות על ידך. \nלהמשיך להציג אותן?"</string>
<string name="inline_done_button" msgid="6043094985588909584">"סיום"</string>
- <string name="inline_ok_button" msgid="603075490581280343">"החלה"</string>
+ <string name="inline_ok_button" msgid="603075490581280343">"אישור"</string>
<string name="inline_keep_showing" msgid="8736001253507073497">"שנמשיך להציג לך את ההתראות האלה?"</string>
<string name="inline_stop_button" msgid="2453460935438696090">"לא, אל תמשיכו"</string>
<string name="inline_deliver_silently_button" msgid="2714314213321223286">"הצגה ללא צליל"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b1736534ffd1..dacdf2146540 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ユーザーを追加"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新しいユーザー"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ゲストを削除しますか?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ゲストをリセットしますか?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"削除"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"リセット"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"おかえりなさい、ゲストさん"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"セッションを続行しますか?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"最初から開始"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 09d5f9f6e3af..8366b2f48927 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Пайдаланушы қосу"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Жаңа пайдаланушы"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Қонақты жою керек пе?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Қонақ сеансы бастапқы күйге қайтарылсын ба?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданбалар мен деректер жойылады."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Алып тастау"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Бастапқы күйге қайтару"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Қош келдіңіз, қонақ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансты жалғастыру керек пе?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Қайта бастау"</string>
@@ -668,7 +666,7 @@
<string name="enable_demo_mode" msgid="3180345364745966431">"Демо режимін қосу"</string>
<string name="show_demo_mode" msgid="3677956462273059726">"Демо режимін көрсету"</string>
<string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
- <string name="status_bar_alarm" msgid="87160847643623352">"Дабыл"</string>
+ <string name="status_bar_alarm" msgid="87160847643623352">"Оятқыш"</string>
<string name="wallet_title" msgid="5369767670735827105">"Әмиян"</string>
<string name="wallet_empty_state_label" msgid="7776761245237530394">"Телефоныңызбен бұрынғыдан да жылдам әрі қауіпсіз сатып алу үшін параметрлерді орнатыңыз."</string>
<string name="wallet_app_button_label" msgid="7123784239111190992">"Барлығын көрсету"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 065a49951dfb..3baa4e1411f1 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"បញ្ចូល​អ្នកប្រើ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"អ្នកប្រើ​ថ្មី"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ដកភ្ញៀវចេញឬ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"កំណត់​ភ្ញៀវឡើង​វិញឬ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យ​ទាំងអស់​ក្នុង​វគ្គ​នេះ​នឹង​ត្រូវ​លុប។"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ដកចេញ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"កំណត់​ឡើងវិញ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"សូម​ស្វាគមន៍​ការ​ត្រឡប់​មកវិញ, ភ្ញៀវ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"តើ​អ្នក​ចង់​បន្ត​វគ្គ​របស់​អ្នក​ទេ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ចាប់ផ្ដើមសាជាថ្មី"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0b21c0f37010..7f57da18de82 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ಬಳಕೆದಾರರನ್ನು ಸೇರಿಸಿ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ಹೊಸ ಬಳಕೆದಾರರು"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ಅತಿಥಿಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ಅತಿಥಿಯನ್ನು ಮರುಹೊಂದಿಸಬೇಕೆ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಷನ್‌ನಲ್ಲಿನ ಎಲ್ಲ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ತೆಗೆದುಹಾಕಿ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ಮರುಹೊಂದಿಸಿ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ಮತ್ತೆ ಸುಸ್ವಾಗತ, ಅತಿಥಿ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ನಿಮ್ಮ ಸೆಷನ್‌ ಮುಂದುವರಿಸಲು ಇಚ್ಚಿಸುವಿರಾ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ಪ್ರಾರಂಭಿಸಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 80415d531d39..ab80f7f3acdc 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"사용자 추가"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"신규 사용자"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"게스트를 삭제하시겠습니까?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"게스트를 초기화하시겠습니까?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"삭제"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"초기화"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"게스트 세션 진행"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"세션을 계속 진행하시겠습니까?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"다시 시작"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2474fe1f25b5..037a765870d4 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Колдонуучу кошуу"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Жаңы колдонуучу"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Конокту алып саласызбы?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Конок сеансын баштапкы абалга келтиресизби?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана маалыматтар өчүрүлөт."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Өчүрүү"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Баштапкы абалга келтирүү"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Кайтып келишиңиз менен!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Сеансыңызды улантасызбы?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Кайра баштоо"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 106f7f20a5ba..4cdc8a5fcb4e 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ເພີ່ມຜູ້ໃຊ້"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ຜູ່ໃຊ້ໃໝ່"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ລຶບ​ແຂກ​ບໍ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ຣີເຊັດແຂກບໍ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯ​ແລະ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ໃນ​ເຊດ​ຊັນ​ນີ້​ຈະ​ຖືກ​ລຶບ​ອອກ."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ລຶບ​"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ຣີເຊັດ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ຍິນ​ດີ​ຕ້ອນ​ຮັບ​ກັບ​ມາ, ຜູ້ຢ້ຽມຢາມ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ທ່ານ​ຕ້ອງ​ການ​ສືບ​ຕໍ່​ເຊດ​ຊັນ​ຂອງ​ທ່ານບໍ່?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ເລີ່ມຕົ້ນໃຫມ່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 44dc8bb6aa30..ce64e4c3d765 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Pridėti naudotoją"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Naujas naudotojas"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Pašalinti svečią?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Nustatyti svečią iš naujo?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Pašalinti"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Nustatyti iš naujo"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Sveiki sugrįžę, svety!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ar norite tęsti sesiją?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Pradėti iš naujo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b846be4491f3..518a28b6d483 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lietotāja pievienošana"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Jauns lietotājs"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vai noņemt viesi?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vai atiestatīt viesa sesiju?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Noņemt"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Atiestatīt"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Laipni lūdzam atpakaļ, viesi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vai vēlaties turpināt savu sesiju?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Sākt no sākuma"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 535da7a98f87..90f775bcd310 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Додај корисник"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Нов корисник"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Да се отстрани гостинот?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Да се ресетира гостинот?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Сите апликации и податоци во сесијата ќе се избришат."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Отстрани"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ресетирај"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добре дојде пак, гостине!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Дали сакате да продолжите со сесијата?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни одново"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 74d087c73d39..6923fef29d4b 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ഉപയോക്താവിനെ ചേര്‍ക്കുക"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"പുതിയ ഉപയോക്താവ്"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"അതിഥിയെ നീക്കംചെയ്യണോ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"അതിഥിയെ റീസെറ്റ് ചെയ്യണോ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"നീക്കംചെയ്യുക"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"റീസെറ്റ് ചെയ്യുക"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"അതിഥി, വീണ്ടും സ്വാഗതം!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"നിങ്ങളുടെ സെഷൻ തുടരണോ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"പുനരാംരംഭിക്കുക"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8dae31d1c7f2..976c2dd420c8 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Хэрэглэгч нэмэх"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Шинэ хэрэглэгч"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Зочныг хасах уу?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Зочныг шинэчлэх үү?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Хасах"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Шинэчлэх"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Эргэн тавтай морилно уу!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Та үргэлжлүүлэхийг хүсэж байна уу?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Дахин эхлүүлэх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3aae0640802f..f649ca485d83 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"वापरकर्ता जोडा"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नवीन वापरकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथी काढायचे?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"अतिथीला रीसेट करायचे आहे का?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अ‍ॅप्स आणि डेटा हटवला जाईल."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"काढा"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रीसेट करा"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"अतिथी, तुमचे पुन्‍हा स्‍वागत आहे!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तुम्ही तुमचे सत्र सुरू ठेवू इच्छिता?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"येथून सुरू करा"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रीनचा काही भाग मॅग्निफाय करा"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"स्विच करा"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"अ‍ॅक्सेसिबिलिटी जेश्चर हे आता अ‍ॅक्सेसिबिलिटी बटण आहे \n\n"<annotation id="link">"सेटिंग्ज पाहा"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"तुम्ही अ‍ॅक्सेसिबिलिटी जेश्चरवरून बटणवर स्विच करू शकता \n\n"<annotation id="link">"सेटिंग्ज"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्‍यामध्ये हलवा"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f3838c4ce802..50342920080c 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Tambah pengguna"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Pengguna baharu"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alih keluar tetamu?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Tetapkan semula tetamu?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alih keluar"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Tetapkan semula"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Selamat kembali, tetamu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Adakah anda ingin meneruskan sesi anda?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Mulakan semula"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 9a8fc20fd6c4..efe716e9d04a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"အသုံးပြုသူ ထည့်ရန်"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"အသုံးပြုသူ အသစ်"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ဧည့်သည်ကို ဖယ်မလား။"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ဧည့်သည်ကို ပြင်ဆင်သတ်မှတ်မလား။"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ဖယ်ထုတ်ပါ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ပြင်ဆင်သတ်မှတ်ရန်"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ဧည့်သည်ကို ပြန်လည် ကြိုဆိုပါသည်။"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"သင်၏ စက်ရှင်ကို ဆက်လုပ်လိုပါသလား။"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ပြန်စပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 71ae67261280..2f07a3e56ffd 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Legg til brukere"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny bruker"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vil du fjerne gjesten?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vil du tilbakestille gjesten?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle appene og all informasjon i denne økten slettes."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Fjern"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Tilbakestill"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Velkommen tilbake, gjest!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vil du fortsette økten?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Start på nytt"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0006f7f824a3..10311b048e2f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -437,7 +437,7 @@
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"एपहरू बदल्न द्रुत गतिमा दायाँतिर ड्र्याग गर्नुहोस्"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"परिदृश्य टगल गर्नुहोस्"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"चार्ज भयो"</string>
- <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै"</string>
+ <string name="expanded_header_battery_charging" msgid="1717522253171025549">"चार्ज हुँदै छ"</string>
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण नभएसम्म"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"चार्ज भइरहेको छैन"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"नेटवर्क \n अनुगमनमा हुन सक्छ"</string>
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"प्रयोगकर्ता थप्नुहोस्"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"नयाँ प्रयोगकर्ता"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"अतिथि हटाउने हो?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"अतिथि सत्र रिसेट गर्ने हो?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"हटाउनुहोस्"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"रिसेट गर्नुहोस्"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"तपाईंलाई फेरि स्वागत छ, अतिथि"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"तपाईं आफ्नो सत्र जारी गर्न चाहनुहुन्छ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"सुरु गर्नुहोस्"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"स्क्रिनको केही भाग म्याग्निफाइ गर्नुहोस्"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"बदल्नुहोस्"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"एक्सेसिबिलिटी इसाराका स्थानमा एक्सेसिबिलिटी बटन प्रयोग हुन थालेको छ\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"तपाईं एक्सेसिबिलिटी जेस्चरको साटो बटन प्रयोग गर्न सक्नुहुन्छ\n\n"<annotation id="link">"सेटिङ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"यो बटन केही बेर नदेखिने पार्न किनारातिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सिरानको बायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सिरानको दायाँतिर सार्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 944753ad570b..8bd41deb9499 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Gebruiker toevoegen"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nieuwe gebruiker"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Gast verwijderen?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Gastsessie resetten?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps en gegevens in deze sessie worden verwijderd."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Verwijderen"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetten"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welkom terug, gast!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Wil je doorgaan met je sessie?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Opnieuw starten"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 1dcb1434bc29..8fede329cff3 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ଉପଯୋଗକର୍ତ୍ତାଙ୍କୁ ଯୋଗ କରନ୍ତୁ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ନୂଆ ଉପଯୋଗକର୍ତ୍ତା"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ଅତିଥିଙ୍କୁ କାଢ଼ିଦେବେ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ଅତିଥିଙ୍କୁ ରିସେଟ୍ କରିବେ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍‌ ଓ ଡାଟା ଡିଲିଟ୍‌ ହୋଇଯିବ।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"କାଢ଼ିଦିଅନ୍ତୁ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ରିସେଟ୍ କରନ୍ତୁ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ପୁଣି ସ୍ୱାଗତ, ଅତିଥି!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ଆପଣ ନିଜର ସେସନ୍ ଜାରି ରଖିବାକୁ ଚାହାଁନ୍ତି କି?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ଆରମ୍ଭ କରନ୍ତୁ"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"ସ୍କ୍ରିନର ଅଂଶ ମାଗ୍ନିଫାଏ କରନ୍ତୁ"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"ସ୍ୱିଚ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"ଆକ୍ସେସିବିଲିଟୀ ଜେଶ୍ଚରକୁ ଆକ୍ସେସିବିଲିଟୀ ବଟନରେ ପରିବର୍ତ୍ତନ କରାଯାଇଛି\n\n"<annotation id="link">"ସେଟିଂସ୍ ଦେଖନ୍ତୁ"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"ଆପଣ ଆକ୍ସେସିବିଲିଟୀ ଜେଶ୍ଚରରୁ ଏକ ବଟନକୁ ସ୍ୱିଚ୍ କରିପାରିବେ\n\n"<annotation id="link">"ସେଟିଂସ୍"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଏହାକୁ ଗୋଟିଏ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0f687a142544..da10cb48b364 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"ਵਰਤੋਂਕਾਰ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ਨਵਾਂ ਵਰਤੋਂਕਾਰ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ਕੀ ਮਹਿਮਾਨ ਹਟਾਉਣਾ ਹੈ?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ਕੀ ਗੈਸਟ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿੱਚ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟਾ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਏਗਾ।"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ਹਟਾਓ"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ਰੀਸੈੱਟ ਕਰੋ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ਮਹਿਮਾਨ, ਫਿਰ ਤੁਹਾਡਾ ਸੁਆਗਤ ਹੈ!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ਕੀ ਤੁਸੀਂ ਆਪਣਾ ਸੈਸ਼ਨ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e822d936eca4..704d38459735 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodaj użytkownika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nowy użytkownik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Usunąć gościa?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Zresetować sesję gościa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Usuń"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetuj"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Witaj ponownie, Gościu!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcesz kontynuować sesję?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Rozpocznij nową"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ad41e5535e6d..e4dbca5eb8e3 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Redefinir sessão de visitante?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Redefinir"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 738e91644681..a9cb3dc88fa1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Adicionar utilizador"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo utilizador"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover o convidado?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Pretende repor a sessão de convidado?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Repor"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bem-vindo de volta, convidado!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Pretende continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ad41e5535e6d..e4dbca5eb8e3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Adicionar usuário"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Novo usuário"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Remover visitante?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Redefinir sessão de visitante?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Remover"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Redefinir"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Você voltou, visitante!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Quer continuar a sessão?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Recomeçar"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3f9a576156d5..42c8dbbf17e3 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Adăugați un utilizator"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Utilizator nou"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ștergeți invitatul?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Resetați invitatul?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ștergeți"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetați"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Bine ați revenit în sesiunea pentru invitați!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vreți să continuați sesiunea?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Începeți din nou"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 67091b957467..e324c35312d8 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Добавить пользователя"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Новый пользователь"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Удалить аккаунт гостя?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Сбросить гостевой сеанс?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Удалить"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Сбросить"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Рады видеть вас снова!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Продолжить сеанс?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Начать заново"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 3a8b51c49117..6c82ad58a25f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"පරිශීලකයෙක් එක් කරන්න"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"නව පරිශීලකයා"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"අමුත්තාන් ඉවත් කරන්නද?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"ආගන්තුකයා යළි සකසන්නද?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ඉවත් කරන්න"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"යළි සකසන්න"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"නැවත සාදරයෙන් පිළිගනිමු, අමුත්තා!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"ඔබගේ සැසිය දිගටම කරගෙන යෑමට ඔබට අවශ්‍යද?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"යළි මුල සිට අරඹන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 19a871e461d3..31bea134ab32 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Pridať používateľa"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nový používateľ"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Odstrániť hosťa?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Chcete resetovať reláciu hosťa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrániť"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Resetovať"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Hosť, vitajte späť!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Chcete v relácii pokračovať?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začať odznova"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index c58343a9fd9e..420e8cb195ca 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -484,12 +484,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Dodajanje uporabnika"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Nov uporabnik"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Želite odstraniti gosta?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Želite ponastaviti gosta?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Odstrani"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ponastavi"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Znova pozdravljeni, gost!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Želite nadaljevati sejo?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Začni znova"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 334b2ed0a603..e4238d27047d 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Shto përdorues"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Përdorues i ri"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Të hiqet i ftuari?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Të rivendoset vizitori?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Hiq"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Rivendos"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Mirë se erdhe, i ftuar!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Dëshiron ta vazhdosh sesionin tënd?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Fillo nga e para"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e4a1bea6f998..4e82fd739dae 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -482,12 +482,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Додај корисника"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Нови корисник"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Желите ли да уклоните госта?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Желите ли да ресетујете сесију госта?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Уклони"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Ресетуј"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Добро дошли назад, госте!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Желите ли да наставите сесију?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Почни из почетка"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3ceef49a21e7..390a7bc268e3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Lägg till användare"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Ny användare"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Vill du ta bort gästen?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Vill du återställa gästsessionen?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ta bort"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Återställ"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Välkommen tillbaka som gäst!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Vill du fortsätta sessionen?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Börja om"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 0a4e05923f89..99bf399b3c1b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Ongeza mtumiaji"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Mtumiaji mpya"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Ungependa kumwondoa mgeni?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Ungependa kubadilisha kipindi cha mgeni?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Ondoa"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Badilisha"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Karibu tena mgeni!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Je, unataka kuendelea na kipindi chako?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Anza upya"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 9f8e6364e55d..da80b85b38bf 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -36,10 +36,6 @@
<!-- On tablets this is just the close_handle_height -->
<dimen name="peek_height">@dimen/close_handle_height</dimen>
- <!-- The margin between the clock and the notifications on Keyguard. See
- keyguard_clock_height_fraction_* for the difference between min and max.-->
- <dimen name="keyguard_clock_notifications_margin">44dp</dimen>
-
<!-- Height of the status bar header bar when on Keyguard -->
<dimen name="status_bar_header_height_keyguard">60dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5dc158195ddc..7e3b412072f0 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"பயனரைச் சேர்"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"புதியவர்"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"கெஸ்ட்டை அகற்றவா?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"விருந்தினர் அமர்வை மீட்டமைக்கவா?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"அகற்று"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"மீட்டமை"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"நல்வரவு!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"உங்கள் அமர்வைத் தொடர விருப்பமா?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"மீண்டும் தொடங்கு"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 348c37ae2e60..1f7146f98d75 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"యూజర్‌ను జోడించండి"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"కొత్త వినియోగదారు"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"గెస్ట్‌ను తీసివేయాలా?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"గెస్ట్ సెషన్‌ను రీసెట్ చేయాలా?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్‌లోని అన్ని యాప్‌లు మరియు డేటా తొలగించబడతాయి."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"తీసివేయి"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"రీసెట్ చేయండి"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"గెస్ట్‌కు తిరిగి స్వాగతం!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"మీరు మీ సెషన్‌ని కొనసాగించాలనుకుంటున్నారా?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"మొదటి నుండి ప్రారంభించు"</string>
@@ -1038,8 +1036,7 @@
<string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"స్క్రీన్‌లో భాగాన్ని మాగ్నిఫై చేయండి"</string>
<string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"స్విచ్ చేయి"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="4431046858918714564">"యాక్సెసిబిలిటీ బటన్, యాక్సెసిబిలిటీ సంజ్ఞను భర్తీ చేసింది\n\n"<annotation id="link">"సెట్టింగ్‌లను చూడండి"</annotation></string>
- <!-- no translation found for accessibility_floating_button_switch_migration_tooltip (6248529129221218770) -->
- <skip />
+ <string name="accessibility_floating_button_switch_migration_tooltip" msgid="6248529129221218770">"మీరు యాక్సెసిబిలిటీ సంజ్ఞ నుండి బటన్ మధ్య మారవచ్చు\n\n"<annotation id="link">"సెట్టింగ్‌లు"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్‌ను చివరకు తరలించండి"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ఎగువ ఎడమ వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ఎగువ కుడి వైపునకు తరలించు"</string>
diff --git a/packages/SystemUI/res/values-television/colors.xml b/packages/SystemUI/res/values-television/colors.xml
index e5f3b4768fe2..566f6b229bc9 100644
--- a/packages/SystemUI/res/values-television/colors.xml
+++ b/packages/SystemUI/res/values-television/colors.xml
@@ -19,4 +19,22 @@
<resources>
<color name="volume_dialog_background_color">#E61F232B</color>
<color name="volume_dialog_background_color_above_blur">#C71F232B</color>
+
+ <color name="bottom_sheet_icon_color">#D2E3FC</color>
+
+ <color name="bottom_sheet_title_color">#E8F0FE</color>
+ <color name="bottom_sheet_body_color">#D2E3FC</color>
+
+ <color name="bottom_sheet_background_color">#1F232C</color>
+ <color name="bottom_sheet_background_color_with_blur">#AA1A2734</color>
+
+ <color name="bottom_sheet_button_background_color_focused">#E8F0FE</color>
+ <color name="bottom_sheet_button_background_color_unfocused">#0FE8EAED</color>
+
+ <color name="bottom_sheet_button_text_color_focused">#DB202124</color>
+ <color name="bottom_sheet_button_text_color_unfocused">#B5E8EAED</color>
+
+ <color name="privacy_circle">#5BB974</color> <!-- g400 -->
+ <color name="privacy_icon_tint">#30302A</color>
+ <color name="privacy_chip_dot_bg_tint">#66000000</color>
</resources>
diff --git a/packages/SystemUI/res/values-television/dimens.xml b/packages/SystemUI/res/values-television/dimens.xml
index 7626db93dd76..c258fcc4273a 100644
--- a/packages/SystemUI/res/values-television/dimens.xml
+++ b/packages/SystemUI/res/values-television/dimens.xml
@@ -18,7 +18,42 @@
<!-- Opacity at which the background for the shutdown UI will be drawn. -->
<item name="shutdown_scrim_behind_alpha" format="float" type="dimen">1.0</item>
- <dimen name="privacy_chip_icon_margin">3dp</dimen>
- <dimen name="privacy_chip_icon_padding">8dp</dimen>
- <dimen name="privacy_chip_icon_size">13dp</dimen>
+ <dimen name="bottom_sheet_padding_horizontal">32dp</dimen>
+ <dimen name="bottom_sheet_padding_vertical">24dp</dimen>
+
+ <dimen name="bottom_sheet_icon_size">42dp</dimen>
+ <dimen name="bottom_sheet_icon_margin">8dp</dimen>
+ <dimen name="bottom_sheet_title_margin_bottom">18dp</dimen>
+ <dimen name="bottom_sheet_details_margin_bottom">8dp</dimen>
+
+ <dimen name="bottom_sheet_actions_width">296dp</dimen>
+ <dimen name="bottom_sheet_actions_spacing">12dp</dimen>
+ <item name="bottom_sheet_button_selection_scaled" format="float" type="dimen">1.1</item>
+ <dimen name="bottom_sheet_button_width">232dp</dimen>
+ <dimen name="bottom_sheet_button_padding_horizontal">20dp</dimen>
+ <dimen name="bottom_sheet_button_padding_vertical">16dp</dimen>
+
+ <dimen name="bottom_sheet_corner_radius">24dp</dimen>
+ <dimen name="bottom_sheet_button_corner_radius">10dp</dimen>
+
+ <dimen name="bottom_sheet_min_height">208dp</dimen>
+ <dimen name="bottom_sheet_margin">24dp</dimen>
+ <dimen name="bottom_sheet_background_blur_radius">120dp</dimen>
+
+ <dimen name="privacy_chip_margin">12dp</dimen>
+ <dimen name="privacy_chip_icon_margin_in_between">9dp</dimen>
+ <dimen name="privacy_chip_padding_horizontal">9dp</dimen>
+ <dimen name="privacy_chip_icon_size">12dp</dimen>
+ <dimen name="privacy_chip_height">24dp</dimen>
+ <dimen name="privacy_chip_min_width">30dp</dimen>
+ <dimen name="privacy_chip_radius">12dp</dimen>
+
+ <dimen name="privacy_chip_dot_size">8dp</dimen>
+ <dimen name="privacy_chip_dot_radius">4dp</dimen>
+ <dimen name="privacy_chip_dot_margin_horizontal">8dp</dimen>
+
+ <dimen name="privacy_chip_dot_bg_width">24dp</dimen>
+ <dimen name="privacy_chip_dot_bg_height">18dp</dimen>
+ <dimen name="privacy_chip_dot_bg_radius">9dp</dimen>
+
</resources> \ No newline at end of file
diff --git a/packages/SystemUI/res/values-television/integers.xml b/packages/SystemUI/res/values-television/integers.xml
index 587497edfdfb..b265d7812229 100644
--- a/packages/SystemUI/res/values-television/integers.xml
+++ b/packages/SystemUI/res/values-television/integers.xml
@@ -20,4 +20,6 @@
Value 81 corresponds to BOTTOM|CENTER_HORIZONTAL.
Value 21 corresponds to RIGHT|CENTER_VERTICAL. -->
<integer name="volume_dialog_gravity">21</integer>
+
+ <integer name="privacy_chip_animation_millis">300</integer>
</resources>
diff --git a/packages/SystemUI/res/values-television/styles.xml b/packages/SystemUI/res/values-television/styles.xml
index 00217fb39b93..0fb789863bd9 100644
--- a/packages/SystemUI/res/values-television/styles.xml
+++ b/packages/SystemUI/res/values-television/styles.xml
@@ -28,4 +28,34 @@
<item name="android:textColorPrimaryInverse">@color/tv_volume_dialog_accent</item>
<item name="android:dialogCornerRadius">@dimen/volume_dialog_panel_width_half</item>
</style>
+
+ <style name="BottomSheet" parent="Theme.Leanback">
+ <item name="android:windowIsFloating">true</item>
+ <item name="android:windowActivityTransitions">true</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:backgroundDimAmount">0.2</item>
+ </style>
+
+ <style name="BottomSheet.TitleText">
+ <item name="android:textSize">28sp</item>
+ <item name="android:textColor">@color/bottom_sheet_title_color</item>
+ </style>
+
+ <style name="BottomSheet.BodyText">
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/bottom_sheet_body_color</item>
+ </style>
+
+ <style name="BottomSheet.ActionItem">
+ <item name="android:layout_width">@dimen/bottom_sheet_button_width</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">left|center_vertical</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">@color/bottom_sheet_button_text_color</item>
+ <item name="android:background">@drawable/bottom_sheet_button_background</item>
+ <item name="android:paddingHorizontal">@dimen/bottom_sheet_button_padding_horizontal</item>
+ <item name="android:paddingVertical">@dimen/bottom_sheet_button_padding_vertical</item>
+ <item name="android:stateListAnimator">@anim/tv_bottom_sheet_button_state_list_animator</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d6eec3fd4fcf..b21d22faf958 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"เพิ่มผู้ใช้"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"ผู้ใช้ใหม่"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"ต้องการนำผู้ใช้ชั่วคราวออกไหม"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"รีเซ็ตผู้เข้าร่วมไหม"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"นำออก"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"รีเซ็ต"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"ยินดีต้อนรับผู้เข้าร่วมกลับมาอีกครั้ง"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"คุณต้องการอยู่ในเซสชันต่อไปไหม"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"เริ่มต้นใหม่"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 0a7bdacc69c8..5b48488f18fe 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Magdagdag ng user"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Bagong user"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Alisin ang bisita?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"I-reset ang session ng bisita?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Alisin"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"I-reset"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Welcome ulit, bisita!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Gusto mo bang ipagpatuloy ang iyong session?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Magsimulang muli"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 80e29fb5df6d..8a3d467fbe58 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Kullanıcı ekle"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Yeni kullanıcı"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Misafir oturumu kaldırılsın mı?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Misafir oturumu sıfırlansın mı?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Kaldır"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Sıfırla"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Misafir kullanıcı, tekrar hoşgeldiniz"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Oturumunuza devam etmek istiyor musunuz?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Baştan başla"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 930bb0586753..efece98d635e 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"صارف کو شامل کریں"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"نیا صارف"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"مہمان کو ہٹائیں؟"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"مہمان کو ری سیٹ کریں؟"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"ہٹائیں"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"ری سیٹ کریں"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"مہمان، پھر سے خوش آمدید!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"کیا آپ اپنا سیشن جاری رکھنا چاہتے ہیں؟"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"دوبارہ شروع کریں"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 241cfb222a18..c337d08102fc 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Thêm người dùng"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Người dùng mới"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Xóa phiên khách?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Đặt lại phiên khách?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Xóa"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Đặt lại"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Chào mừng bạn trở lại!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Bạn có muốn tiếp tục phiên của mình không?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Bắt đầu lại"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 25cc331d993b..9592b2d6aa5c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"添加用户"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新用户"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"要移除访客吗?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重置访客会话吗?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重置"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"访客,欢迎回来!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"要继续您的会话吗?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新开始"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 5c58081f5035..b9ea4b0159e3 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"加入使用者"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客工作階段嗎?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重設"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客您好,歡迎回來!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"您要繼續您的工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5c4c3b15e997..7d82bf5a723b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"新增使用者"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"新使用者"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"移除訪客?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"要重設訪客工作階段嗎?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會遭到刪除。"</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"移除"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"重設"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"訪客你好,歡迎回來!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"你要繼續這個工作階段嗎?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"重新開始"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 647102ac4895..a44c6ff9b744 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -480,12 +480,10 @@
<string name="user_add_user" msgid="4336657383006913022">"Engeza umsebenzisi"</string>
<string name="user_new_user_name" msgid="2019166282704195789">"Umsebenzisi omusha"</string>
<string name="guest_exit_guest_dialog_title" msgid="5015697561580641422">"Susa isivakashi?"</string>
- <!-- no translation found for guest_reset_guest_dialog_title (8904781614074479690) -->
- <skip />
+ <string name="guest_reset_guest_dialog_title" msgid="8904781614074479690">"Setha kabusha isimenywa?"</string>
<string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Zonke izinhlelo zokusebenza nedatha kulesi sikhathi zizosuswa."</string>
<string name="guest_exit_guest_dialog_remove" msgid="7505817591242703757">"Susa"</string>
- <!-- no translation found for guest_reset_guest_dialog_remove (4359825585658228699) -->
- <skip />
+ <string name="guest_reset_guest_dialog_remove" msgid="4359825585658228699">"Setha kabusha"</string>
<string name="guest_wipe_session_title" msgid="7147965814683990944">"Siyakwamukela futhi, sivakashi!"</string>
<string name="guest_wipe_session_message" msgid="3393823610257065457">"Ingabe ufuna ukuqhubeka ngesikhathi sakho?"</string>
<string name="guest_wipe_session_wipe" msgid="8056836584445473309">"Qala phansi"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9678affa96a7..2a1bee5344ec 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -445,6 +445,9 @@
<!-- Adjust the theme on fully custom and decorated custom view notifications -->
<bool name="config_adjustThemeOnNotificationCustomViews">false</bool>
+ <!-- Notifications are sized to match the width of two (of 4) qs tiles in landscape. -->
+ <bool name="config_skinnyNotifsInLandscape">true</bool>
+
<!-- If true, enable the advance anti-falsing classifier on the lockscreen. On some devices it
does not work well, particularly with noisy touchscreens. Note that disabling it may
increase the rate of unintentional unlocks. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3e4684c9b2d6..7525a9b1c19c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -735,8 +735,8 @@
<!-- Minimum distance the user has to drag down to go to the full shade. -->
<dimen name="keyguard_drag_down_min_distance">100dp</dimen>
- <!-- The margin between the clock and the notifications on Keyguard.-->
- <dimen name="keyguard_clock_notifications_margin">30dp</dimen>
+ <!-- The margin between the status view and the notifications on Keyguard.-->
+ <dimen name="keyguard_status_view_bottom_margin">20dp</dimen>
<!-- Minimum margin between clock and status bar -->
<dimen name="keyguard_clock_top_margin">36dp</dimen>
<!-- The margin between top of clock and bottom of lock icon. -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index ef6212d4f354..a28d1747f2fe 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -205,6 +205,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
}
}
+ int getNotificationIconAreaHeight() {
+ return mNotificationIconAreaController.getHeight();
+ }
+
@Override
protected void onViewDetached() {
if (CUSTOM_CLOCKS_ENABLED) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 123c0e63d7d1..2096c310744d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -187,10 +187,11 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
}
/**
- * Get the height of the keyguard status view.
+ * Get the height of the keyguard status view without the notification icon area, as that's
+ * only visible on AOD.
*/
- public int getHeight() {
- return mView.getHeight();
+ public int getLockscreenHeight() {
+ return mView.getHeight() - mKeyguardClockSwitchController.getNotificationIconAreaHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 7cd43eff8e2a..cff6cf1f53f1 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -19,6 +19,7 @@ package com.android.systemui.accessibility.floatingmenu;
import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
import android.content.Context;
+import android.os.UserHandle;
import android.text.TextUtils;
import androidx.annotation.MainThread;
@@ -40,11 +41,11 @@ public class AccessibilityFloatingMenuController implements
AccessibilityButtonModeObserver.ModeChangedListener,
AccessibilityButtonTargetsObserver.TargetsChangedListener {
- private final Context mContext;
private final AccessibilityButtonModeObserver mAccessibilityButtonModeObserver;
private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private Context mContext;
@VisibleForTesting
IAccessibilityFloatingMenu mFloatingMenu;
private int mBtnMode;
@@ -79,6 +80,7 @@ public class AccessibilityFloatingMenuController implements
@Override
public void onUserSwitchComplete(int userId) {
+ mContext = mContext.createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
mBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
mBtnTargets =
mAccessibilityButtonTargetsObserver.getCurrentAccessibilityButtonTargets();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
index 5bb55222e09b..e891e5b64b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility.floatingmenu;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.util.MathUtils.constrain;
import static android.util.MathUtils.sq;
import static android.view.WindowInsets.Type.ime;
@@ -200,6 +201,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mListView = listView;
mWindowManager = context.getSystemService(WindowManager.class);
+ mLastConfiguration = new Configuration(getResources().getConfiguration());
mAdapter = new AccessibilityTargetAdapter(mTargets);
mUiHandler = createUiHandler();
mPosition = position;
@@ -243,7 +245,6 @@ public class AccessibilityFloatingMenuView extends FrameLayout
}
});
- mLastConfiguration = new Configuration(getResources().getConfiguration());
initListView();
updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment);
@@ -567,8 +568,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
final int currentX = (int) event.getX();
final int currentY = (int) event.getY();
+ final int marginStartEnd = getMarginStartEndWith(mLastConfiguration);
final Rect touchDelegateBounds =
- new Rect(mMargin, mMargin, mMargin + getLayoutWidth(), mMargin + getLayoutHeight());
+ new Rect(marginStartEnd, mMargin, marginStartEnd + getLayoutWidth(),
+ mMargin + getLayoutHeight());
if (action == MotionEvent.ACTION_DOWN
&& touchDelegateBounds.contains(currentX, currentY)) {
mIsDownInEnlargedTouchArea = true;
@@ -682,15 +685,13 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mListView.setLayoutManager(layoutManager);
mListView.addOnItemTouchListener(this);
mListView.animate().setInterpolator(new OvershootInterpolator());
- updateListView();
+ updateListViewWith(mLastConfiguration);
addView(mListView);
}
- private void updateListView() {
- final LayoutParams layoutParams = (FrameLayout.LayoutParams) mListView.getLayoutParams();
- layoutParams.setMargins(mMargin, mMargin, mMargin, mMargin);
- mListView.setLayoutParams(layoutParams);
+ private void updateListViewWith(Configuration configuration) {
+ updateMarginWith(configuration);
final int elevation =
getResources().getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation);
@@ -719,13 +720,15 @@ public class AccessibilityFloatingMenuView extends FrameLayout
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mLastConfiguration.setTo(newConfig);
+
final int diff = newConfig.diff(mLastConfiguration);
if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) {
updateAccessibilityTitle(mCurrentLayoutParams);
}
updateDimensions();
- updateListView();
+ updateListViewWith(newConfig);
updateItemViewWith(mSizeType);
updateColor();
updateStrokeWith(newConfig.uiMode, mAlignment);
@@ -733,8 +736,6 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
updateScrollModeWith(hasExceededMaxLayoutHeight());
setSystemGestureExclusion();
-
- mLastConfiguration.setTo(newConfig);
}
@VisibleForTesting
@@ -756,11 +757,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
}
private int getMinWindowX() {
- return -mMargin;
+ return -getMarginStartEndWith(mLastConfiguration);
}
private int getMaxWindowX() {
- return mScreenWidth - mMargin - getLayoutWidth();
+ return mScreenWidth - getMarginStartEndWith(mLastConfiguration) - getLayoutWidth();
}
private int getMaxWindowY() {
@@ -805,6 +806,15 @@ public class AccessibilityFloatingMenuView extends FrameLayout
return layoutBottomY > imeY ? (layoutBottomY - imeY) : 0;
}
+ private void updateMarginWith(Configuration configuration) {
+ // Avoid overlapping with system bars under landscape mode, update the margins of the menu
+ // to align the edge of system bars.
+ final int marginStartEnd = getMarginStartEndWith(configuration);
+ final LayoutParams layoutParams = (FrameLayout.LayoutParams) mListView.getLayoutParams();
+ layoutParams.setMargins(marginStartEnd, mMargin, marginStartEnd, mMargin);
+ mListView.setLayoutParams(layoutParams);
+ }
+
private void updateOffsetWith(@ShapeType int shapeType, @Alignment int side) {
final float halfWidth = getLayoutWidth() / 2.0f;
final float offset = (shapeType == ShapeType.OVAL) ? 0 : halfWidth;
@@ -896,6 +906,12 @@ public class AccessibilityFloatingMenuView extends FrameLayout
return (mPadding + mIconHeight) * mTargets.size() + mPadding;
}
+ private int getMarginStartEndWith(Configuration configuration) {
+ return configuration != null
+ && configuration.orientation == ORIENTATION_PORTRAIT
+ ? mMargin : 0;
+ }
+
private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) {
return sizeType == SizeType.SMALL
? getSmallSizeResIdWith(itemCount)
@@ -932,7 +948,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
}
private int getWindowWidth() {
- return mMargin * 2 + getLayoutWidth();
+ return getMarginStartEndWith(mLastConfiguration) * 2 + getLayoutWidth();
}
private int getWindowHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index ec930b0c41d1..11412f41f578 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -67,6 +67,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -111,6 +112,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final PowerManager mPowerManager;
@NonNull private final AccessibilityManager mAccessibilityManager;
+ @NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Nullable private final UdfpsHbmProvider mHbmProvider;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@@ -507,6 +509,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull FalsingManager falsingManager,
@NonNull PowerManager powerManager,
@NonNull AccessibilityManager accessibilityManager,
+ @NonNull LockscreenShadeTransitionController lockscreenShadeTransitionController,
@NonNull ScreenLifecycle screenLifecycle,
@Nullable Vibrator vibrator,
@NonNull Optional<UdfpsHbmProvider> hbmProvider) {
@@ -529,6 +532,7 @@ public class UdfpsController implements DozeReceiver {
mFalsingManager = falsingManager;
mPowerManager = powerManager;
mAccessibilityManager = accessibilityManager;
+ mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
mHbmProvider = hbmProvider.orElse(null);
screenLifecycle.addObserver(mScreenObserver);
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
@@ -716,6 +720,7 @@ public class UdfpsController implements DozeReceiver {
mFgExecutor,
mDumpManager,
mKeyguardViewMediator,
+ mLockscreenShadeTransitionController,
this
);
case IUdfpsOverlayController.REASON_AUTH_BP:
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 00888dfe48d3..35ca470df523 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -31,6 +31,7 @@ import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -54,6 +55,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final DelayableExecutor mExecutor;
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
+ @NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
@NonNull private final UdfpsController mUdfpsController;
@Nullable private Runnable mCancelDelayedHintRunnable;
@@ -63,6 +65,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
private boolean mFaceDetectRunning;
private boolean mHintShown;
private int mStatusBarState;
+ private float mTransitionToFullShadeProgress;
/**
* hidden amount of pin/pattern/password bouncer
@@ -81,12 +84,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull DelayableExecutor mainDelayableExecutor,
@NonNull DumpManager dumpManager,
@NonNull KeyguardViewMediator keyguardViewMediator,
+ @NonNull LockscreenShadeTransitionController transitionController,
@NonNull UdfpsController udfpsController) {
super(view, statusBarStateController, statusBar, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mExecutor = mainDelayableExecutor;
mKeyguardViewMediator = keyguardViewMediator;
+ mLockScreenShadeTransitionController = transitionController;
mUdfpsController = udfpsController;
}
@@ -116,6 +121,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
updatePauseAuth();
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+ mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(this);
}
@Override
@@ -127,6 +133,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
+ if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
+ mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
+ }
if (mCancelDelayedHintRunnable != null) {
mCancelDelayedHintRunnable.run();
@@ -256,11 +265,21 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
}
}
+ /**
+ * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
+ * transitioning yet, while 1.0f means we've fully dragged down.
+ */
+ public void setTransitionToFullShadeProgress(float progress) {
+ mTransitionToFullShadeProgress = progress;
+ updateAlpha();
+ }
+
private void updateAlpha() {
// fade icon on transition to showing bouncer
int alpha = mShowingUdfpsBouncer ? 255
: Math.abs((int) MathUtils.constrainedMap(0f, 255f, .4f, .7f,
mInputBouncerHiddenAmount));
+ alpha *= (1.0f - mTransitionToFullShadeProgress);
mView.setUnpausedAlpha(alpha);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 2dbf30fdd289..de8ed7013ab2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -25,6 +25,7 @@ import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.screenrecord.ScreenRecordDialog;
import com.android.systemui.screenshot.LongScreenshotActivity;
import com.android.systemui.sensorprivacy.SensorUseStartedActivity;
+import com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity;
import com.android.systemui.settings.brightness.BrightnessDialog;
import com.android.systemui.statusbar.tv.notifications.TvNotificationPanelActivity;
import com.android.systemui.tuner.TunerActivity;
@@ -120,4 +121,10 @@ public abstract class DefaultActivityBinder {
@IntoMap
@ClassKey(SensorUseStartedActivity.class)
public abstract Activity bindSensorUseStartedActivity(SensorUseStartedActivity activity);
+
+ /** Inject into TvUnblockSensorActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(TvUnblockSensorActivity.class)
+ public abstract Activity bindTvUnblockSensorActivity(TvUnblockSensorActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 746621dfda27..d85c9a718871 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -231,7 +231,8 @@ public class DependencyProvider {
@Main Handler mainHandler,
UiEventLogger uiEventLogger,
NavigationBarOverlayController navBarOverlayController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ UserTracker userTracker) {
return new NavigationBarController(context,
windowManager,
assistManagerLazy,
@@ -256,7 +257,8 @@ public class DependencyProvider {
mainHandler,
uiEventLogger,
navBarOverlayController,
- configurationController);
+ configurationController,
+ userTracker);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 053d75d96720..954ba797e164 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -63,6 +63,7 @@ import android.service.dreams.IDreamManager;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.view.CrossWindowBlurListeners;
import android.view.IWindowManager;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -139,6 +140,12 @@ public class FrameworkServicesModule {
}
@Provides
+ @Singleton
+ static CrossWindowBlurListeners provideCrossWindowBlurListeners() {
+ return CrossWindowBlurListeners.getInstance();
+ }
+
+ @Provides
@DisplayId
static int provideDisplayId(Context context) {
return context.getDisplayId();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 7b34e52c16e8..455f3c0d6ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -71,7 +71,6 @@ public class DozeTriggers implements DozeMachine.Part {
* Assuming that the screen should start on.
*/
private static boolean sWakeDisplaySensorState = true;
- private Runnable mQuickPickupDozeCancellable;
private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500;
@@ -279,14 +278,14 @@ public class DozeTriggers implements DozeMachine.Part {
boolean isWakeDisplayEvent = isQuickPickup || ((isWakeOnPresence || isWakeOnReach)
&& rawValues != null && rawValues.length > 0 && rawValues[0] != 0);
- if (isWakeOnPresence || isQuickPickup) {
- onWakeScreen(isQuickPickup || isWakeDisplayEvent,
+ if (isWakeOnPresence) {
+ onWakeScreen(isWakeDisplayEvent,
mMachine.isExecutingTransition() ? null : mMachine.getState(),
pulseReason);
} else if (isLongPress) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
null /* onPulseSuppressedListener */);
- } else if (isWakeOnReach) {
+ } else if (isWakeOnReach || isQuickPickup) {
if (isWakeDisplayEvent) {
requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
null /* onPulseSuppressedListener */);
@@ -388,11 +387,7 @@ public class DozeTriggers implements DozeMachine.Part {
*/
private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state, int reason) {
mDozeLog.traceWakeDisplay(wake, reason);
- final boolean isWakeOnPresence = reason == DozeLog.REASON_SENSOR_WAKE_UP;
- final boolean isQuickPickup = reason == DozeLog.REASON_SENSOR_QUICK_PICKUP;
- if (isWakeOnPresence) {
- sWakeDisplaySensorState = wake;
- }
+ sWakeDisplaySensorState = wake;
if (wake) {
proximityCheckThenCall((result) -> {
@@ -405,27 +400,13 @@ public class DozeTriggers implements DozeMachine.Part {
// Log sensor triggered
Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
.ifPresent(mUiEventLogger::log);
-
- if (isQuickPickup) {
- // schedule runnable to go back to DOZE
- onQuickPickup();
- }
- } else if (state == DozeMachine.State.DOZE_AOD && isQuickPickup) {
- // elongate time in DOZE_AOD, schedule new runnable to go back to DOZE
- onQuickPickup();
}
- }, isQuickPickup /* alreadyPerformedProxCheck */, reason);
+ }, false /* alreadyPerformedProxCheck */, reason);
} else {
boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
- boolean pulse = (state == DozeMachine.State.DOZE_REQUEST_PULSE)
- || (state == DozeMachine.State.DOZE_PULSING)
- || (state == DozeMachine.State.DOZE_PULSING_BRIGHT);
- boolean docked = (state == DozeMachine.State.DOZE_AOD_DOCKED);
+
if (!pausing && !paused) {
- if (isQuickPickup && (pulse || docked)) {
- return;
- }
mMachine.requestState(DozeMachine.State.DOZE);
// log wake timeout
mUiEventLogger.log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT);
@@ -433,15 +414,6 @@ public class DozeTriggers implements DozeMachine.Part {
}
}
- private void onQuickPickup() {
- cancelQuickPickupDelayableDoze();
- mQuickPickupDozeCancellable = mMainExecutor.executeDelayed(() -> {
- onWakeScreen(false,
- mMachine.isExecutingTransition() ? null : mMachine.getState(),
- DozeLog.REASON_SENSOR_QUICK_PICKUP);
- }, mDozeParameters.getQuickPickupAodDuration());
- }
-
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
@@ -481,7 +453,6 @@ public class DozeTriggers implements DozeMachine.Part {
mDozeSensors.requestTemporaryDisable();
break;
case FINISH:
- cancelQuickPickupDelayableDoze();
mBroadcastReceiver.unregister(mBroadcastDispatcher);
mDozeHost.removeCallback(mHostCallback);
mDockManager.removeListener(mDockEventListener);
@@ -510,16 +481,6 @@ public class DozeTriggers implements DozeMachine.Part {
}
}
- /**
- * Cancels last scheduled Runnable that transitions to STATE_DOZE (blank screen) after
- * going into STATE_AOD (AOD screen) from the quick pickup gesture.
- */
- private void cancelQuickPickupDelayableDoze() {
- if (mQuickPickupDozeCancellable != null) {
- mQuickPickupDozeCancellable.run();
- mQuickPickupDozeCancellable = null;
- }
- }
private void checkTriggersAtInit() {
if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 3251ab2e4d50..3957a60c5b45 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -32,6 +32,7 @@ import javax.inject.Provider
private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
+private const val DEBUG = false
/**
* Class that is responsible for keeping the view carousel up to date.
@@ -237,7 +238,7 @@ class MediaCarouselController @Inject constructor(
data: SmartspaceMediaData,
shouldPrioritize: Boolean
) {
- Log.d(TAG, "My Smartspace media update is here")
+ if (DEBUG) Log.d(TAG, "Loading Smartspace media update")
if (data.isActive) {
addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
MediaPlayerData.getMediaPlayer(key, null)?.let {
@@ -266,7 +267,7 @@ class MediaCarouselController @Inject constructor(
}
override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
- Log.d(TAG, "My Smartspace media removal request is received")
+ if (DEBUG) Log.d(TAG, "My Smartspace media removal request is received")
if (immediately || visualStabilityManager.isReorderingAllowed) {
onMediaDataRemoved(key)
} else {
@@ -384,7 +385,7 @@ class MediaCarouselController @Inject constructor(
data: SmartspaceMediaData,
shouldPrioritize: Boolean
) {
- Log.d(TAG, "Updating smartspace target in carousel")
+ if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
if (MediaPlayerData.getMediaPlayer(key, null) != null) {
Log.w(TAG, "Skip adding smartspace target in carousel")
return
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index ed6f5505cbd1..df1b07f3e0b2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -453,7 +453,8 @@ class MediaDataManager(
if (smartspaceMediaData.targetId != key) {
return
}
- Log.d(TAG, "Dismissing Smartspace media target")
+
+ if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
if (smartspaceMediaData.isActive) {
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId)
@@ -709,17 +710,19 @@ class MediaDataManager(
override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
if (!allowMediaRecommendations) {
+ if (DEBUG) Log.d(TAG, "Smartspace recommendation is disabled in Settings.")
return
}
val mediaTargets = targets.filterIsInstance<SmartspaceTarget>()
when (mediaTargets.size) {
0 -> {
- Log.d(TAG, "Empty Smartspace media target")
if (!smartspaceMediaData.isActive) {
return
}
- Log.d(TAG, "Set Smartspace media to be inactive for the data update")
+ if (DEBUG) {
+ Log.d(TAG, "Set Smartspace media to be inactive for the data update")
+ }
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId)
notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = false)
@@ -728,13 +731,12 @@ class MediaDataManager(
val newMediaTarget = mediaTargets.get(0)
if (smartspaceMediaData.targetId == newMediaTarget.smartspaceTargetId) {
// The same Smartspace updates can be received. Skip the duplicate updates.
- Log.d(TAG, "Same Smartspace media update exists. Skip loading data.")
- } else {
- Log.d(TAG, "Forwarding Smartspace media update.")
- smartspaceMediaData = toSmartspaceMediaData(newMediaTarget, isActive = true)
- notifySmartspaceMediaDataLoaded(
- smartspaceMediaData.targetId, smartspaceMediaData)
+ return
}
+ if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.")
+ smartspaceMediaData = toSmartspaceMediaData(newMediaTarget, isActive = true)
+ notifySmartspaceMediaDataLoaded(
+ smartspaceMediaData.targetId, smartspaceMediaData)
}
else -> {
// There should NOT be more than 1 Smartspace media update. When it happens, it
@@ -883,7 +885,7 @@ class MediaDataManager(
private fun packageName(target: SmartspaceTarget): String? {
val recommendationList = target.iconGrid
if (recommendationList == null || recommendationList.isEmpty()) {
- Log.d(TAG, "Empty or media recommendation list.")
+ Log.w(TAG, "Empty or null media recommendation list.")
return null
}
for (recommendation in recommendationList) {
@@ -893,7 +895,7 @@ class MediaDataManager(
packageName -> return packageName }
}
}
- Log.d(TAG, "No valid package name is provided.")
+ Log.w(TAG, "No valid package name is provided.")
return null
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 3d1b4fbde56a..186f961ff1b6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -660,15 +660,11 @@ class MediaHierarchyManager @Inject constructor(
return true
}
- if (statusbarState == StatusBarState.KEYGUARD) {
- if (currentLocation == LOCATION_LOCKSCREEN &&
- previousLocation == LOCATION_QS ||
- (currentLocation == LOCATION_QS &&
- previousLocation == LOCATION_LOCKSCREEN)) {
- // We're always fading from lockscreen to keyguard in situations where the player
- // is already fully hidden
- return false
- }
+ if (statusbarState == StatusBarState.KEYGUARD && (currentLocation == LOCATION_LOCKSCREEN ||
+ previousLocation == LOCATION_LOCKSCREEN)) {
+ // We're always fading from lockscreen to keyguard in situations where the player
+ // is already fully hidden
+ return false
}
return mediaFrame.isShownNotFaded || animator.isRunning || animationPending
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 0d5faff65aab..1d6d1f2e4885 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -46,7 +46,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private ViewGroup mConnectedItem;
- private boolean mInclueDynamicGroup;
+ private boolean mIncludeDynamicGroup;
public MediaOutputAdapter(MediaOutputController controller) {
super(controller);
@@ -56,7 +56,6 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
super.onCreateViewHolder(viewGroup, viewType);
-
return new MediaDeviceViewHolder(mHolderView);
}
@@ -66,7 +65,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
if (position == size && mController.isZeroMode()) {
viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
true /* bottomMargin */);
- } else if (mInclueDynamicGroup) {
+ } else if (mIncludeDynamicGroup) {
if (position == 0) {
viewHolder.onBind(CUSTOMIZED_ITEM_DYNAMIC_GROUP, true /* topMargin */,
false /* bottomMargin */);
@@ -76,11 +75,12 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
// from "position - 1".
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices()))
.get(position - 1),
- false /* topMargin */, position == size /* bottomMargin */);
+ false /* topMargin */, position == size /* bottomMargin */, position);
}
} else if (position < size) {
viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
- position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
+ position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */,
+ position);
} else if (DEBUG) {
Log.d(TAG, "Incorrect position: " + position);
}
@@ -88,8 +88,8 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
@Override
public int getItemCount() {
- mInclueDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
- if (mController.isZeroMode() || mInclueDynamicGroup) {
+ mIncludeDynamicGroup = mController.getSelectedMediaDevice().size() > 1;
+ if (mController.isZeroMode() || mIncludeDynamicGroup) {
// Add extra one for "pair new" or dynamic group
return mController.getMediaDevices().size() + 1;
}
@@ -120,15 +120,17 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
}
@Override
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
- super.onBind(device, topMargin, bottomMargin);
- final boolean currentlyConnected = !mInclueDynamicGroup && isCurrentlyConnected(device);
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
+ super.onBind(device, topMargin, bottomMargin, position);
+ final boolean currentlyConnected = !mIncludeDynamicGroup
+ && isCurrentlyConnected(device);
if (currentlyConnected) {
mConnectedItem = mContainerLayout;
}
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
- if (currentlyConnected && mController.isActiveRemoteDevice(device)) {
+ if (currentlyConnected && mController.isActiveRemoteDevice(device)
+ && mController.getSelectableMediaDevice().size() > 0) {
// Init active device layout
mDivider.setVisibility(View.VISIBLE);
mDivider.setTransitionAlpha(1);
@@ -160,6 +162,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setTwoLineLayout(device, true /* bFocused */, true /* showSeekBar */,
false /* showProgressBar */, false /* showSubtitle */);
initSeekbar(device);
+ mCurrentActivePosition = position;
} else {
setSingleLineLayout(getItemTitle(device), false /* bFocused */);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
@@ -186,11 +189,16 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mConnectedItem = mContainerLayout;
mBottomDivider.setVisibility(View.GONE);
mCheckBox.setVisibility(View.GONE);
- mDivider.setVisibility(View.VISIBLE);
- mDivider.setTransitionAlpha(1);
- mAddIcon.setVisibility(View.VISIBLE);
- mAddIcon.setTransitionAlpha(1);
- mAddIcon.setOnClickListener(v -> onEndItemClick());
+ if (mController.getSelectableMediaDevice().size() > 0) {
+ mDivider.setVisibility(View.VISIBLE);
+ mDivider.setTransitionAlpha(1);
+ mAddIcon.setVisibility(View.VISIBLE);
+ mAddIcon.setTransitionAlpha(1);
+ mAddIcon.setOnClickListener(v -> onEndItemClick());
+ } else {
+ mDivider.setVisibility(View.GONE);
+ mAddIcon.setVisibility(View.GONE);
+ }
mTitleIcon.setImageDrawable(getSpeakerDrawable());
final CharSequence sessionName = mController.getSessionName();
final CharSequence title = TextUtils.isEmpty(sessionName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index bcef43c93be4..0890841eb4fb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -64,10 +64,12 @@ public abstract class MediaOutputBaseAdapter extends
Context mContext;
View mHolderView;
boolean mIsDragging;
+ int mCurrentActivePosition;
public MediaOutputBaseAdapter(MediaOutputController controller) {
mController = controller;
mIsDragging = false;
+ mCurrentActivePosition = -1;
}
@Override
@@ -99,6 +101,10 @@ public abstract class MediaOutputBaseAdapter extends
return mIsAnimating;
}
+ int getCurrentActivePosition() {
+ return mCurrentActivePosition;
+ }
+
/**
* ViewHolder for binding device view.
*/
@@ -136,7 +142,7 @@ public abstract class MediaOutputBaseAdapter extends
mCheckBox = view.requireViewById(R.id.check_box);
}
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
mDeviceId = device.getId();
ThreadUtils.postOnBackgroundThread(() -> {
Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
@@ -214,6 +220,9 @@ public abstract class MediaOutputBaseAdapter extends
}
void initSeekbar(MediaDevice device) {
+ if (!mController.isVolumeControlEnabled(device)) {
+ disableSeekBar();
+ }
mSeekBar.setMax(device.getMaxVolume());
mSeekBar.setMin(0);
final int currentVolume = device.getCurrentVolume();
@@ -242,6 +251,7 @@ public abstract class MediaOutputBaseAdapter extends
}
void initSessionSeekbar() {
+ disableSeekBar();
mSeekBar.setMax(mController.getSessionVolumeMax());
mSeekBar.setMin(0);
final int currentVolume = mController.getSessionVolume();
@@ -330,5 +340,10 @@ public abstract class MediaOutputBaseAdapter extends
PorterDuff.Mode.SRC_IN));
return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
+
+ private void disableSeekBar() {
+ mSeekBar.setEnabled(false);
+ mSeekBar.setOnTouchListener((v, event) -> true);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 8a9a6e694658..cdcdf9a1d4de 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -174,7 +174,12 @@ public abstract class MediaOutputBaseDialog extends SystemUIDialog implements
mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
}
if (!mAdapter.isDragging() && !mAdapter.isAnimating()) {
- mAdapter.notifyDataSetChanged();
+ int currentActivePosition = mAdapter.getCurrentActivePosition();
+ if (currentActivePosition >= 0) {
+ mAdapter.notifyItemChanged(currentActivePosition);
+ } else {
+ mAdapter.notifyDataSetChanged();
+ }
}
// Show when remote media session is available
mStopButton.setVisibility(getStopButtonVisibility());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 8fee9253a421..5293c8850267 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -465,6 +465,10 @@ public class MediaOutputController implements LocalMediaManager.DeviceCallback {
|| features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
}
+ boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
+ return !device.getFeatures().contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+ }
+
private final MediaController.Callback mCb = new MediaController.Callback() {
@Override
public void onMetadataChanged(MediaMetadata metadata) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
index 24e076bb22f1..968c3506f39f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupAdapter.java
@@ -68,7 +68,7 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
final int size = mGroupMediaDevices.size();
if (newPosition < size) {
viewHolder.onBind(mGroupMediaDevices.get(newPosition), false /* topMargin */,
- newPosition == (size - 1) /* bottomMargin */);
+ newPosition == (size - 1) /* bottomMargin */, position);
return;
}
if (DEBUG) {
@@ -94,8 +94,8 @@ public class MediaOutputGroupAdapter extends MediaOutputBaseAdapter {
}
@Override
- void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
- super.onBind(device, topMargin, bottomMargin);
+ void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
+ super.onBind(device, topMargin, bottomMargin, position);
mDivider.setVisibility(View.GONE);
mAddIcon.setVisibility(View.GONE);
mBottomDivider.setVisibility(View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index da09793580bb..711bb56dd95a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -129,6 +129,7 @@ import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -199,6 +200,7 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
private final UiEventLogger mUiEventLogger;
+ private final UserTracker mUserTracker;
private Bundle mSavedState;
private NavigationBarView mNavigationBarView;
@@ -232,7 +234,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private boolean mTransientShown;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
- private int mA11yBtnMode;
private LightBarController mLightBarController;
private AutoHideController mAutoHideController;
@@ -459,7 +460,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
SystemActions systemActions,
@Main Handler mainHandler,
NavigationBarOverlayController navbarOverlayController,
- UiEventLogger uiEventLogger) {
+ UiEventLogger uiEventLogger,
+ UserTracker userTracker) {
mContext = context;
mWindowManager = windowManager;
mAccessibilityManager = accessibilityManager;
@@ -484,10 +486,10 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
mUiEventLogger = uiEventLogger;
+ mUserTracker = userTracker;
mNavBarMode = mNavigationModeController.addListener(this);
mAccessibilityButtonModeObserver.addListener(this);
- mA11yBtnMode = mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode();
}
public NavigationBarView getView() {
@@ -1375,8 +1377,9 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
private void setAccessibilityFloatingMenuModeIfNeeded() {
if (QuickStepContract.isGesturalMode(mNavBarMode)) {
- Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
- ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU);
+ Settings.Secure.putIntForUser(mContentResolver,
+ Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
+ ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_CURRENT);
}
}
@@ -1437,7 +1440,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
// If accessibility button is floating menu mode, click and long click state should be
// disabled.
- if (mA11yBtnMode == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
+ if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode()
+ == ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU) {
return 0;
}
@@ -1450,12 +1454,14 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
boolean longPressDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistLongPressHomeEnabledDefault);
- mLongPressHomeEnabled = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0) != 0;
+ mLongPressHomeEnabled = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ASSIST_LONG_PRESS_HOME_ENABLED, longPressDefault ? 1 : 0,
+ mUserTracker.getUserId()) != 0;
boolean gestureDefault = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_assistTouchGestureEnabledDefault);
- mAssistantTouchGestureEnabled = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0) != 0;
+ mAssistantTouchGestureEnabled = Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.ASSIST_TOUCH_GESTURE_ENABLED, gestureDefault ? 1 : 0,
+ mUserTracker.getUserId()) != 0;
if (mOverviewProxyService.getProxy() != null) {
try {
mOverviewProxyService.getProxy().onAssistantAvailable(mAssistantAvailable
@@ -1546,7 +1552,6 @@ public class NavigationBar implements View.OnAttachStateChangeListener,
@Override
public void onAccessibilityButtonModeChanged(int mode) {
- mA11yBtnMode = mode;
updateAccessibilityServicesState(mAccessibilityManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 8b5a537ba242..53592101c3ea 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -57,6 +57,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -116,6 +117,7 @@ public class NavigationBarController implements Callbacks,
private final TaskbarDelegate mTaskbarDelegate;
private int mNavMode;
private boolean mIsTablet;
+ private final UserTracker mUserTracker;
/** A displayId - nav bar maps. */
@VisibleForTesting
@@ -151,7 +153,8 @@ public class NavigationBarController implements Callbacks,
@Main Handler mainHandler,
UiEventLogger uiEventLogger,
NavigationBarOverlayController navBarOverlayController,
- ConfigurationController configurationController) {
+ ConfigurationController configurationController,
+ UserTracker userTracker) {
mContext = context;
mWindowManager = windowManager;
mAssistManagerLazy = assistManagerLazy;
@@ -184,6 +187,7 @@ public class NavigationBarController implements Callbacks,
mNavigationModeController.addListener(this);
mTaskbarDelegate = new TaskbarDelegate(mOverviewProxyService);
mIsTablet = isTablet(mContext.getResources().getConfiguration());
+ mUserTracker = userTracker;
}
@Override
@@ -361,7 +365,8 @@ public class NavigationBarController implements Callbacks,
mSystemActions,
mHandler,
mNavBarOverlayController,
- mUiEventLogger);
+ mUiEventLogger,
+ mUserTracker);
mNavigationBars.put(displayId, navBar);
View navigationBarView = navBar.createView(savedState);
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java b/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java
new file mode 100644
index 000000000000..e5479badcb0a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/PrivacyChipDrawable.java
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.privacy.television;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+import androidx.annotation.Keep;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * Drawable that can go from being the background of the privacy icons to a small dot.
+ * The icons are not included.
+ */
+public class PrivacyChipDrawable extends Drawable {
+
+ private static final String TAG = PrivacyChipDrawable.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private float mWidth;
+ private float mHeight;
+ private float mMarginEnd;
+ private float mRadius;
+ private int mDotAlpha;
+ private int mBgAlpha;
+
+ private float mTargetWidth;
+ private final int mMinWidth;
+ private final int mIconWidth;
+ private final int mIconPadding;
+ private final int mBgWidth;
+ private final int mBgHeight;
+ private final int mBgRadius;
+ private final int mDotSize;
+
+ private final AnimatorSet mFadeIn;
+ private final AnimatorSet mFadeOut;
+ private final AnimatorSet mCollapse;
+ private final AnimatorSet mExpand;
+ private Animator mWidthAnimator;
+
+ private final Paint mChipPaint;
+ private final Paint mBgPaint;
+
+ private boolean mIsRtl;
+
+ private boolean mIsExpanded = true;
+
+ private PrivacyChipDrawableListener mListener;
+
+ interface PrivacyChipDrawableListener {
+ void onFadeOutFinished();
+ }
+
+ public PrivacyChipDrawable(Context context) {
+ mChipPaint = new Paint();
+ mChipPaint.setStyle(Paint.Style.FILL);
+ mChipPaint.setColor(context.getColor(R.color.privacy_circle));
+ mChipPaint.setAlpha(mDotAlpha);
+ mChipPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+
+ mBgPaint = new Paint();
+ mBgPaint.setStyle(Paint.Style.FILL);
+ mBgPaint.setColor(context.getColor(R.color.privacy_chip_dot_bg_tint));
+ mBgPaint.setAlpha(mBgAlpha);
+ mBgPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+
+ mBgWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_dot_bg_width);
+ mBgHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_dot_bg_height);
+ mBgRadius = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_dot_bg_radius);
+
+ mMinWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_min_width);
+ mIconWidth = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
+ mIconPadding = context.getResources().getDimensionPixelSize(
+ R.dimen.privacy_chip_icon_margin_in_between);
+ mDotSize = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_dot_size);
+
+ mWidth = mMinWidth;
+ mHeight = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_height);
+ mRadius = context.getResources().getDimensionPixelSize(R.dimen.privacy_chip_radius);
+
+ mExpand = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_expand);
+ mExpand.setTarget(this);
+
+ mCollapse = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_collapse);
+ mCollapse.setTarget(this);
+
+ mFadeIn = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_fade_in);
+ mFadeIn.setTarget(this);
+
+ mFadeOut = (AnimatorSet) AnimatorInflater.loadAnimator(context,
+ R.anim.tv_privacy_chip_fade_out);
+ mFadeOut.setTarget(this);
+ mFadeOut.addListener(new Animator.AnimatorListener() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mCancelled = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCancelled && mListener != null) {
+ if (DEBUG) Log.d(TAG, "Fade-out complete");
+ mListener.onFadeOutFinished();
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ // no-op
+ }
+ });
+ }
+
+ /**
+ * Pass null to remove listener.
+ */
+ public void setListener(@Nullable PrivacyChipDrawableListener listener) {
+ this.mListener = listener;
+ }
+
+ /**
+ * Call once the view that is showing the drawable is visible to start fading the chip in.
+ */
+ public void startInitialFadeIn() {
+ if (DEBUG) Log.d(TAG, "initial fade-in");
+ mFadeIn.start();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ Rect bounds = getBounds();
+
+ int centerVertical = (bounds.bottom - bounds.top) / 2;
+ // Dot background
+ RectF bgBounds = new RectF(
+ mIsRtl ? bounds.left : bounds.right - mBgWidth,
+ centerVertical - mBgHeight / 2f,
+ mIsRtl ? bounds.left + mBgWidth : bounds.right,
+ centerVertical + mBgHeight / 2f);
+ if (DEBUG) Log.v(TAG, "bg: " + bgBounds.toShortString());
+ canvas.drawRoundRect(bgBounds, mBgRadius, mBgRadius, mBgPaint);
+
+ // Icon background / dot
+ RectF greenBounds = new RectF(
+ mIsRtl ? bounds.left + mMarginEnd : bounds.right - mWidth - mMarginEnd,
+ centerVertical - mHeight / 2,
+ mIsRtl ? bounds.left + mWidth + mMarginEnd : bounds.right - mMarginEnd,
+ centerVertical + mHeight / 2);
+ if (DEBUG) Log.v(TAG, "green: " + greenBounds.toShortString());
+ canvas.drawRoundRect(greenBounds, mRadius, mRadius, mChipPaint);
+ }
+
+ private void animateToNewTargetWidth(float width) {
+ if (DEBUG) Log.d(TAG, "new target width: " + width);
+ if (width != mTargetWidth) {
+ mTargetWidth = width;
+ Animator newWidthAnimator = ObjectAnimator.ofFloat(this, "width", mTargetWidth);
+ newWidthAnimator.start();
+ if (mWidthAnimator != null) {
+ mWidthAnimator.cancel();
+ }
+ mWidthAnimator = newWidthAnimator;
+ }
+ }
+
+ private void expand() {
+ if (DEBUG) Log.d(TAG, "expanding");
+ if (mIsExpanded) {
+ return;
+ }
+ mIsExpanded = true;
+
+ mExpand.start();
+ mCollapse.cancel();
+ }
+
+ /**
+ * Starts the animation to a dot.
+ */
+ public void collapse() {
+ if (DEBUG) Log.d(TAG, "collapsing");
+ if (!mIsExpanded) {
+ return;
+ }
+ mIsExpanded = false;
+
+ animateToNewTargetWidth(mDotSize);
+ mCollapse.start();
+ mExpand.cancel();
+ }
+
+ /**
+ * Fades out the view if 0 icons are to be shown, expands the chip if it has been collapsed and
+ * makes the width of the chip adjust to the amount of icons to be shown.
+ * Should not be called when only the order of the icons was changed as the chip will expand
+ * again without there being any real update.
+ *
+ * @param iconCount Can be 0 to fade out the chip.
+ */
+ public void updateIcons(int iconCount) {
+ if (DEBUG) Log.d(TAG, "updating icons: " + iconCount);
+
+ // calculate chip size and use it for end value of animation that is specified in code,
+ // not xml
+ if (iconCount == 0) {
+ // fade out if there are no icons
+ mFadeOut.start();
+
+ mWidthAnimator.cancel();
+ mFadeIn.cancel();
+ mExpand.cancel();
+ mCollapse.cancel();
+ return;
+ }
+
+ mFadeOut.cancel();
+ expand();
+ animateToNewTargetWidth(mMinWidth + (iconCount - 1) * (mIconWidth + mIconPadding));
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ setDotAlpha(alpha);
+ setBgAlpha(alpha);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mDotAlpha;
+ }
+
+ /**
+ * Set alpha value the green part of the chip.
+ */
+ @Keep
+ public void setDotAlpha(int alpha) {
+ if (DEBUG) Log.v(TAG, "dot alpha updated to: " + alpha);
+ mDotAlpha = alpha;
+ mChipPaint.setAlpha(alpha);
+ }
+
+ @Keep
+ public int getDotAlpha() {
+ return mDotAlpha;
+ }
+
+ /**
+ * Set alpha value of the background of the chip.
+ */
+ @Keep
+ public void setBgAlpha(int alpha) {
+ if (DEBUG) Log.v(TAG, "bg alpha updated to: " + alpha);
+ mBgAlpha = alpha;
+ mBgPaint.setAlpha(alpha);
+ }
+
+ @Keep
+ public int getBgAlpha() {
+ return mBgAlpha;
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ // no-op
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ /**
+ * The radius of the green part of the chip, not the background.
+ */
+ @Keep
+ public void setRadius(float radius) {
+ mRadius = radius;
+ invalidateSelf();
+ }
+
+ /**
+ * @return The radius of the green part of the chip, not the background.
+ */
+ @Keep
+ public float getRadius() {
+ return mRadius;
+ }
+
+ /**
+ * Height of the green part of the chip, not including the background.
+ */
+ @Keep
+ public void setHeight(float height) {
+ mHeight = height;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Height of the green part of the chip, not including the background.
+ */
+ @Keep
+ public float getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Width of the green part of the chip, not including the background.
+ */
+ @Keep
+ public void setWidth(float width) {
+ mWidth = width;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Width of the green part of the chip, not including the background.
+ */
+ @Keep
+ public float getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Margin at the end of the green part of the chip, so that it will be placed in the middle of
+ * the rounded rectangle in the background.
+ */
+ @Keep
+ public void setMarginEnd(float marginEnd) {
+ mMarginEnd = marginEnd;
+ invalidateSelf();
+ }
+
+ /**
+ * @return Margin at the end of the green part of the chip, so that it will be placed in the
+ * middle of the rounded rectangle in the background.
+ */
+ @Keep
+ public float getMarginEnd() {
+ return mMarginEnd;
+ }
+
+ /**
+ * Sets the layout direction.
+ */
+ public void setRtl(boolean isRtl) {
+ mIsRtl = isRtl;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
index 5ab7bd88e49b..e4f5cde37f1d 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
+++ b/packages/SystemUI/src/com/android/systemui/privacy/television/TvOngoingPrivacyChip.java
@@ -25,9 +25,10 @@ import android.annotation.IntDef;
import android.annotation.UiThread;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -38,15 +39,20 @@ import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import androidx.annotation.NonNull;
+
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.privacy.PrivacyChipBuilder;
import com.android.systemui.privacy.PrivacyItem;
import com.android.systemui.privacy.PrivacyItemController;
+import com.android.systemui.privacy.PrivacyType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
@@ -56,9 +62,10 @@ import javax.inject.Inject;
* recording audio, accessing the camera or accessing the location.
*/
@SysUISingleton
-public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemController.Callback {
+public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemController.Callback,
+ PrivacyChipDrawable.PrivacyChipDrawableListener {
private static final String TAG = "TvOngoingPrivacyChip";
- static final boolean DEBUG = false;
+ private static final boolean DEBUG = false;
// This title is used in CameraMicIndicatorsPermissionTest and
// RecognitionServiceMicIndicatorTest.
@@ -68,7 +75,8 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
@IntDef(prefix = {"STATE_"}, value = {
STATE_NOT_SHOWN,
STATE_APPEARING,
- STATE_SHOWN,
+ STATE_EXPANDED,
+ STATE_COLLAPSED,
STATE_DISAPPEARING
})
public @interface State {
@@ -76,46 +84,58 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
private static final int STATE_NOT_SHOWN = 0;
private static final int STATE_APPEARING = 1;
- private static final int STATE_SHOWN = 2;
- private static final int STATE_DISAPPEARING = 3;
+ private static final int STATE_EXPANDED = 2;
+ private static final int STATE_COLLAPSED = 3;
+ private static final int STATE_DISAPPEARING = 4;
- private static final int ANIMATION_DURATION_MS = 200;
+ private static final int EXPANDED_DURATION_MS = 4000;
+ public final int mAnimationDurationMs;
private final Context mContext;
private final PrivacyItemController mPrivacyItemController;
- private View mIndicatorView;
+ private ViewGroup mIndicatorView;
private boolean mViewAndWindowAdded;
private ObjectAnimator mAnimator;
private boolean mMicCameraIndicatorFlagEnabled;
- private boolean mLocationIndicatorEnabled;
- private List<PrivacyItem> mPrivacyItems;
+ private boolean mAllIndicatorsEnabled;
+
+ @NonNull
+ private List<PrivacyItem> mPrivacyItems = Collections.emptyList();
private LinearLayout mIconsContainer;
private final int mIconSize;
private final int mIconMarginStart;
+ private PrivacyChipDrawable mChipDrawable;
+
+ private final Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+ private final Runnable mCollapseRunnable = this::collapseChip;
+
@State
private int mState = STATE_NOT_SHOWN;
@Inject
public TvOngoingPrivacyChip(Context context, PrivacyItemController privacyItemController) {
super(context);
- Log.d(TAG, "Privacy chip running without id");
+ if (DEBUG) Log.d(TAG, "Privacy chip running");
mContext = context;
mPrivacyItemController = privacyItemController;
Resources res = mContext.getResources();
- mIconMarginStart = Math.round(res.getDimension(R.dimen.privacy_chip_icon_margin));
+ mIconMarginStart = Math.round(
+ res.getDimension(R.dimen.privacy_chip_icon_margin_in_between));
mIconSize = res.getDimensionPixelSize(R.dimen.privacy_chip_icon_size);
+ mAnimationDurationMs = res.getInteger(R.integer.privacy_chip_animation_millis);
+
mMicCameraIndicatorFlagEnabled = privacyItemController.getMicCameraAvailable();
- mLocationIndicatorEnabled = privacyItemController.getLocationAvailable();
+ mAllIndicatorsEnabled = privacyItemController.getAllIndicatorsAvailable();
if (DEBUG) {
Log.d(TAG, "micCameraIndicators: " + mMicCameraIndicatorFlagEnabled);
- Log.d(TAG, "locationIndicators: " + mLocationIndicatorEnabled);
+ Log.d(TAG, "allIndicators: " + mAllIndicatorsEnabled);
}
}
@@ -125,69 +145,145 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
}
@Override
- public void onPrivacyItemsChanged(List<PrivacyItem> privacyItems) {
+ public void onPrivacyItemsChanged(@NonNull List<PrivacyItem> privacyItems) {
if (DEBUG) Log.d(TAG, "PrivacyItemsChanged");
- mPrivacyItems = privacyItems;
- updateUI();
+
+ List<PrivacyItem> updatedPrivacyItems = new ArrayList<>(privacyItems);
+ // Never show the location indicator on tv.
+ if (updatedPrivacyItems.removeIf(
+ privacyItem -> privacyItem.getPrivacyType() == PrivacyType.TYPE_LOCATION)) {
+ if (DEBUG) Log.v(TAG, "Removed the location item");
+ }
+
+ if (isChipDisabled()) {
+ fadeOutIndicator();
+ mPrivacyItems = updatedPrivacyItems;
+ return;
+ }
+
+ // Do they have the same elements? (order doesn't matter)
+ if (updatedPrivacyItems.size() == mPrivacyItems.size()
+ && mPrivacyItems.containsAll(updatedPrivacyItems)) {
+ if (DEBUG) Log.d(TAG, "List wasn't updated");
+ return;
+ }
+
+ mPrivacyItems = updatedPrivacyItems;
+ updateChip();
+ }
+
+ private void updateChip() {
+ if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
+
+ if (mPrivacyItems.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "removing indicator (state: " + stateToString(mState) + ")");
+ fadeOutIndicator();
+ return;
+ }
+
+ if (DEBUG) Log.d(TAG, "Current state: " + stateToString(mState));
+ switch (mState) {
+ case STATE_NOT_SHOWN:
+ createAndShowIndicator();
+ break;
+ case STATE_APPEARING:
+ case STATE_EXPANDED:
+ updateIcons();
+ collapseLater();
+ break;
+ case STATE_COLLAPSED:
+ case STATE_DISAPPEARING:
+ mState = STATE_EXPANDED;
+ updateIcons();
+ animateIconAppearance();
+ break;
+ }
+ }
+
+ /**
+ * Collapse the chip EXPANDED_DURATION_MS from now.
+ */
+ private void collapseLater() {
+ mUiThreadHandler.removeCallbacks(mCollapseRunnable);
+ if (DEBUG) Log.d(TAG, "chip will collapse in " + EXPANDED_DURATION_MS + "ms");
+ mUiThreadHandler.postDelayed(mCollapseRunnable, EXPANDED_DURATION_MS);
+ }
+
+ private void collapseChip() {
+ if (DEBUG) Log.d(TAG, "collapseChip");
+
+ if (mState != STATE_EXPANDED) {
+ return;
+ }
+ mState = STATE_COLLAPSED;
+
+ if (mChipDrawable != null) {
+ mChipDrawable.collapse();
+ }
+ animateIconDisappearance();
}
@Override
public void onFlagMicCameraChanged(boolean flag) {
if (DEBUG) Log.d(TAG, "mic/camera indicators enabled: " + flag);
mMicCameraIndicatorFlagEnabled = flag;
+ updateChipOnFlagChanged();
}
@Override
- public void onFlagLocationChanged(boolean flag) {
- if (DEBUG) Log.d(TAG, "location indicators enabled: " + flag);
- mLocationIndicatorEnabled = flag;
+ public void onFlagAllChanged(boolean flag) {
+ if (DEBUG) Log.d(TAG, "all indicators enabled: " + flag);
+ mAllIndicatorsEnabled = flag;
+ updateChipOnFlagChanged();
}
- private void updateUI() {
- if (DEBUG) Log.d(TAG, mPrivacyItems.size() + " privacy items");
+ private boolean isChipDisabled() {
+ return !(mMicCameraIndicatorFlagEnabled || mAllIndicatorsEnabled);
+ }
- if ((mMicCameraIndicatorFlagEnabled || mLocationIndicatorEnabled)
- && !mPrivacyItems.isEmpty()) {
- if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) {
- showIndicator();
- } else {
- if (DEBUG) Log.d(TAG, "only updating icons");
- PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
- setIcons(builder.generateIcons(), mIconsContainer);
- mIconsContainer.requestLayout();
- }
+ private void updateChipOnFlagChanged() {
+ if (isChipDisabled()) {
+ fadeOutIndicator();
} else {
- hideIndicatorIfNeeded();
+ updateChip();
}
}
@UiThread
- private void hideIndicatorIfNeeded() {
+ private void fadeOutIndicator() {
if (mState == STATE_NOT_SHOWN || mState == STATE_DISAPPEARING) return;
+ mUiThreadHandler.removeCallbacks(mCollapseRunnable);
+
if (mViewAndWindowAdded) {
mState = STATE_DISAPPEARING;
- animateDisappearance();
+ animateIconDisappearance();
} else {
// Appearing animation has not started yet, as we were still waiting for the View to be
// laid out.
mState = STATE_NOT_SHOWN;
removeIndicatorView();
}
+ if (mChipDrawable != null) {
+ mChipDrawable.updateIcons(0);
+ }
}
@UiThread
- private void showIndicator() {
+ private void createAndShowIndicator() {
mState = STATE_APPEARING;
+ if (mIndicatorView != null || mViewAndWindowAdded) {
+ removeIndicatorView();
+ }
+
// Inflate the indicator view
- mIndicatorView = LayoutInflater.from(mContext).inflate(
+ mIndicatorView = (ViewGroup) LayoutInflater.from(mContext).inflate(
R.layout.tv_ongoing_privacy_chip, null);
- // 1. Set alpha to 0.
+ // 1. Set icon alpha to 0.
// 2. Wait until the window is shown and the view is laid out.
// 3. Start a "fade in" (alpha) animation.
- mIndicatorView.setAlpha(0f);
mIndicatorView
.getViewTreeObserver()
.addOnGlobalLayoutListener(
@@ -196,20 +292,35 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
public void onGlobalLayout() {
// State could have changed to NOT_SHOWN (if all the recorders are
// already gone)
- if (mState != STATE_APPEARING) return;
+ if (mState != STATE_APPEARING) {
+ return;
+ }
mViewAndWindowAdded = true;
// Remove the observer
mIndicatorView.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
- animateAppearance();
+ animateIconAppearance();
+ mChipDrawable.startInitialFadeIn();
}
});
+ final boolean isRtl = mContext.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL;
+ if (DEBUG) Log.d(TAG, "is RTL: " + isRtl);
+
+ mChipDrawable = new PrivacyChipDrawable(mContext);
+ mChipDrawable.setListener(this);
+ mChipDrawable.setRtl(isRtl);
+ ImageView chipBackground = mIndicatorView.findViewById(R.id.chip_drawable);
+ if (chipBackground != null) {
+ chipBackground.setImageDrawable(mChipDrawable);
+ }
+
mIconsContainer = mIndicatorView.findViewById(R.id.icons_container);
- PrivacyChipBuilder builder = new PrivacyChipBuilder(mContext, mPrivacyItems);
- setIcons(builder.generateIcons(), mIconsContainer);
+ mIconsContainer.setAlpha(0f);
+ updateIcons();
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WRAP_CONTENT,
@@ -217,19 +328,19 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
- layoutParams.gravity = Gravity.TOP | Gravity.END;
+ layoutParams.gravity = Gravity.TOP | (isRtl ? Gravity.LEFT : Gravity.RIGHT);
layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
layoutParams.packageName = mContext.getPackageName();
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.addView(mIndicatorView, layoutParams);
-
}
- private void setIcons(List<Drawable> icons, ViewGroup iconsContainer) {
- iconsContainer.removeAllViews();
+ private void updateIcons() {
+ List<Drawable> icons = new PrivacyChipBuilder(mContext, mPrivacyItems).generateIcons();
+ mIconsContainer.removeAllViews();
for (int i = 0; i < icons.size(); i++) {
Drawable icon = icons.get(i);
- icon.mutate().setTint(Color.WHITE);
+ icon.mutate().setTint(mContext.getColor(R.color.privacy_icon_tint));
ImageView imageView = new ImageView(mContext);
imageView.setImageDrawable(icon);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
@@ -241,22 +352,25 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
imageView.setLayoutParams(layoutParams);
}
}
+ if (mChipDrawable != null) {
+ mChipDrawable.updateIcons(icons.size());
+ }
}
- private void animateAppearance() {
- animateAlphaTo(1f);
+ private void animateIconAppearance() {
+ animateIconAlphaTo(1f);
}
- private void animateDisappearance() {
- animateAlphaTo(0f);
+ private void animateIconDisappearance() {
+ animateIconAlphaTo(0f);
}
- private void animateAlphaTo(final float endValue) {
+ private void animateIconAlphaTo(float endValue) {
if (mAnimator == null) {
if (DEBUG) Log.d(TAG, "set up animator");
mAnimator = new ObjectAnimator();
- mAnimator.setTarget(mIndicatorView);
+ mAnimator.setTarget(mIconsContainer);
mAnimator.setProperty(View.ALPHA);
mAnimator.addListener(new AnimatorListenerAdapter() {
boolean mCancelled;
@@ -280,7 +394,7 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
// and then onAnimationEnd(...). We, however, only want to proceed here if the
// animation ended "naturally".
if (!mCancelled) {
- onAnimationFinished();
+ onIconAnimationFinished();
}
}
});
@@ -289,19 +403,37 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
mAnimator.cancel();
}
- final float currentValue = mIndicatorView.getAlpha();
+ final float currentValue = mIconsContainer.getAlpha();
+ if (currentValue == endValue) {
+ if (DEBUG) Log.d(TAG, "alpha not changing");
+ return;
+ }
if (DEBUG) Log.d(TAG, "animate alpha to " + endValue + " from " + currentValue);
- mAnimator.setDuration((int) (Math.abs(currentValue - endValue) * ANIMATION_DURATION_MS));
+ mAnimator.setDuration(mAnimationDurationMs);
mAnimator.setFloatValues(endValue);
mAnimator.start();
}
- private void onAnimationFinished() {
- if (DEBUG) Log.d(TAG, "onAnimationFinished");
+ @Override
+ public void onFadeOutFinished() {
+ if (DEBUG) Log.d(TAG, "drawable fade-out finished");
+
+ if (mState == STATE_DISAPPEARING) {
+ removeIndicatorView();
+ mState = STATE_NOT_SHOWN;
+ }
+ }
+
+ private void onIconAnimationFinished() {
+ if (DEBUG) Log.d(TAG, "onAnimationFinished (icon fade)");
+
+ if (mState == STATE_APPEARING || mState == STATE_EXPANDED) {
+ collapseLater();
+ }
if (mState == STATE_APPEARING) {
- mState = STATE_SHOWN;
+ mState = STATE_EXPANDED;
} else if (mState == STATE_DISAPPEARING) {
removeIndicatorView();
mState = STATE_NOT_SHOWN;
@@ -312,14 +444,39 @@ public class TvOngoingPrivacyChip extends SystemUI implements PrivacyItemControl
if (DEBUG) Log.d(TAG, "removeIndicatorView");
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- if (windowManager != null) {
+ if (windowManager != null && mIndicatorView != null) {
windowManager.removeView(mIndicatorView);
}
mIndicatorView = null;
mAnimator = null;
+ if (mChipDrawable != null) {
+ mChipDrawable.setListener(null);
+ mChipDrawable = null;
+ }
+
mViewAndWindowAdded = false;
}
+ /**
+ * Used in debug logs.
+ */
+ private String stateToString(@State int state) {
+ switch (state) {
+ case STATE_NOT_SHOWN:
+ return "NOT_SHOWN";
+ case STATE_APPEARING:
+ return "APPEARING";
+ case STATE_EXPANDED:
+ return "EXPANDED";
+ case STATE_COLLAPSED:
+ return "COLLAPSED";
+ case STATE_DISAPPEARING:
+ return "DISAPPEARING";
+ default:
+ return "INVALID";
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index edfbed04f70d..6660081006cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -297,7 +297,7 @@ public class QSContainerImpl extends FrameLayout {
// start margin of next page).
qsPanelController.setPageMargin(mSideMargins);
} else if (view == mHeader) {
- // No content padding for the header.
+ quickStatusBarHeaderController.setContentMargins(mContentPadding, mContentPadding);
} else {
view.setPaddingRelative(
mContentPadding,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 2d0d87dcadee..bcce87a51097 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -46,6 +46,7 @@ import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
public class QSDetail extends LinearLayout {
@@ -83,6 +84,8 @@ public class QSDetail extends LinearLayout {
private boolean mSwitchState;
private QSFooter mFooter;
+ private NotificationsQuickSettingsContainer mContainer;
+
public QSDetail(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@@ -115,6 +118,10 @@ public class QSDetail extends LinearLayout {
mClipper = new QSDetailClipper(this);
}
+ public void setContainer(NotificationsQuickSettingsContainer container) {
+ mContainer = container;
+ }
+
/** */
public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
QSFooter footer) {
@@ -242,6 +249,9 @@ public class QSDetail extends LinearLayout {
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
animateDetailVisibleDiff(x, y, visibleDiff, listener);
+ if (mContainer != null) {
+ mContainer.setDetailShowing(showingDetail);
+ }
}
protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 7b8a6a0a8d0e..c28c649b0306 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -293,6 +293,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void setContainer(ViewGroup container) {
if (container instanceof NotificationsQuickSettingsContainer) {
mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
+ mQSDetail.setContainer((NotificationsQuickSettingsContainer) container);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0bb0a3f7bad4..c70eaffcaeb6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -425,7 +425,7 @@ public class QSPanel extends LinearLayout implements Tunable {
LinearLayout.LayoutParams layoutParams = (LayoutParams) hostView.getLayoutParams();
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
- layoutParams.weight = horizontal ? 1.2f : 0;
+ layoutParams.weight = horizontal ? 1f : 0;
// Add any bottom margin, such that the total spacing is correct. This is only
// necessary if the view isn't horizontal, since otherwise the padding is
// carried in the parent of this view (to ensure correct vertical alignment)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index cbdcad5cf385..76076f6c2761 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -177,7 +177,6 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mView.onAttach(mIconManager, mQSExpansionPathInterpolator);
mDemoModeController.addCallback(mDemoModeReceiver);
- mHeaderQsPanelController.setContentMargins(0, 0);
}
@Override
@@ -253,6 +252,10 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
return mMicCameraIndicatorsEnabled || mLocationIndicatorsEnabled;
}
+ public void setContentMargins(int marginStart, int marginEnd) {
+ mHeaderQsPanelController.setContentMargins(marginStart, marginEnd);
+ }
+
private static class ClockDemoModeReceiver implements DemoMode {
private Clock mClockView;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
index 730702ec8685..51cc32ad39c1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageTileSet.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.HardwareRenderer;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
+import android.graphics.Region;
import android.graphics.RenderNode;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@@ -46,7 +47,6 @@ class ImageTileSet {
private static final String TAG = "ImageTileSet";
- private CallbackRegistry<OnBoundsChangedListener, ImageTileSet, Rect> mOnBoundsListeners;
private CallbackRegistry<OnContentChangedListener, ImageTileSet, Rect> mContentListeners;
@Inject
@@ -54,14 +54,6 @@ class ImageTileSet {
mHandler = handler;
}
- interface OnBoundsChangedListener {
- /**
- * Reports an update to the bounding box that contains all active tiles. These are virtual
- * (capture) coordinates which can be either negative or positive.
- */
- void onBoundsChanged(int left, int top, int right, int bottom);
- }
-
interface OnContentChangedListener {
/**
* Mark as dirty and rebuild display list.
@@ -70,25 +62,9 @@ class ImageTileSet {
}
private final List<ImageTile> mTiles = new ArrayList<>();
- private final Rect mBounds = new Rect();
+ private final Region mRegion = new Region();
private final Handler mHandler;
- void addOnBoundsChangedListener(OnBoundsChangedListener listener) {
- if (mOnBoundsListeners == null) {
- mOnBoundsListeners = new CallbackRegistry<>(
- new NotifierCallback<OnBoundsChangedListener, ImageTileSet, Rect>() {
- @Override
- public void onNotifyCallback(OnBoundsChangedListener callback,
- ImageTileSet sender,
- int arg, Rect newBounds) {
- callback.onBoundsChanged(newBounds.left, newBounds.top, newBounds.right,
- newBounds.bottom);
- }
- });
- }
- mOnBoundsListeners.add(listener);
- }
-
void addOnContentChangedListener(OnContentChangedListener listener) {
if (mContentListeners == null) {
mContentListeners = new CallbackRegistry<>(
@@ -110,14 +86,8 @@ class ImageTileSet {
mHandler.post(() -> addTile(tile));
return;
}
- final Rect newBounds = new Rect(mBounds);
- final Rect newRect = tile.getLocation();
mTiles.add(tile);
- newBounds.union(newRect);
- if (!newBounds.equals(mBounds)) {
- mBounds.set(newBounds);
- notifyBoundsChanged(mBounds);
- }
+ mRegion.op(tile.getLocation(), mRegion, Region.Op.UNION);
notifyContentChanged();
}
@@ -127,12 +97,6 @@ class ImageTileSet {
}
}
- private void notifyBoundsChanged(Rect bounds) {
- if (mOnBoundsListeners != null) {
- mOnBoundsListeners.notifyCallbacks(this, 0, bounds);
- }
- }
-
/**
* Returns a drawable to paint the combined contents of the tiles. Drawable dimensions are
* zero-based and map directly to {@link #getLeft()}, {@link #getTop()}, {@link #getRight()},
@@ -153,6 +117,15 @@ class ImageTileSet {
return mTiles.size();
}
+ /**
+ * @return the bounding rect around any gaps in the tiles.
+ */
+ Rect getGaps() {
+ Region difference = new Region();
+ difference.op(mRegion.getBounds(), mRegion, Region.Op.DIFFERENCE);
+ return difference.getBounds();
+ }
+
ImageTile get(int i) {
return mTiles.get(i);
}
@@ -182,41 +155,40 @@ class ImageTileSet {
}
int getLeft() {
- return mBounds.left;
+ return mRegion.getBounds().left;
}
int getTop() {
- return mBounds.top;
+ return mRegion.getBounds().top;
}
int getRight() {
- return mBounds.right;
+ return mRegion.getBounds().right;
}
int getBottom() {
- return mBounds.bottom;
+ return mRegion.getBounds().bottom;
}
int getWidth() {
- return mBounds.width();
+ return mRegion.getBounds().width();
}
int getHeight() {
- return mBounds.height();
+ return mRegion.getBounds().height();
}
void clear() {
if (mTiles.isEmpty()) {
return;
}
- mBounds.setEmpty();
+ mRegion.setEmpty();
Iterator<ImageTile> i = mTiles.iterator();
while (i.hasNext()) {
ImageTile next = i.next();
next.close();
i.remove();
}
- notifyBoundsChanged(mBounds);
notifyContentChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 669046591170..3c830cc374ab 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -453,14 +453,6 @@ public class ScreenshotView extends FrameLayout implements
mCornerSizeX / (mOrientationPortrait ? bounds.width() : bounds.height());
final float currentScale = 1 / cornerScale;
- mScreenshotPreview.setScaleX(currentScale);
- mScreenshotPreview.setScaleY(currentScale);
-
- if (mAccessibilityManager.isEnabled()) {
- mDismissButton.setAlpha(0);
- mDismissButton.setVisibility(View.VISIBLE);
- }
-
AnimatorSet dropInAnimation = new AnimatorSet();
ValueAnimator flashInAnimator = ValueAnimator.ofFloat(0, 1);
flashInAnimator.setDuration(SCREENSHOT_FLASH_IN_DURATION_MS);
@@ -491,6 +483,20 @@ public class ScreenshotView extends FrameLayout implements
ValueAnimator toCorner = ValueAnimator.ofFloat(0, 1);
toCorner.setDuration(SCREENSHOT_TO_CORNER_Y_DURATION_MS);
+
+ toCorner.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mScreenshotPreview.setScaleX(currentScale);
+ mScreenshotPreview.setScaleY(currentScale);
+ mScreenshotPreview.setVisibility(View.VISIBLE);
+ if (mAccessibilityManager.isEnabled()) {
+ mDismissButton.setAlpha(0);
+ mDismissButton.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+
float xPositionPct =
SCREENSHOT_TO_CORNER_X_DURATION_MS / (float) SCREENSHOT_TO_CORNER_Y_DURATION_MS;
float dismissPct =
@@ -534,13 +540,6 @@ public class ScreenshotView extends FrameLayout implements
}
});
- toCorner.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- mScreenshotPreview.setVisibility(View.VISIBLE);
- }
- });
-
mScreenshotFlash.setAlpha(0f);
mScreenshotFlash.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
index 94e314948779..ce6e46937c25 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureClient.java
@@ -56,6 +56,7 @@ import javax.inject.Inject;
public class ScrollCaptureClient {
private static final int TILE_SIZE_PX_MAX = 4 * (1024 * 1024);
private static final int TILES_PER_PAGE = 2; // increase once b/174571735 is addressed
+ private static final int MAX_TILES = 30;
@VisibleForTesting
static final int MATCH_ANY_TASK = ActivityTaskManager.INVALID_TASK_ID;
@@ -83,11 +84,12 @@ public class ScrollCaptureClient {
int getMaxTiles();
/**
- * @return the maximum combined capture height for this session, in pixels.
+ * Target pixel height for acquisition this session. Session may yield more or less data
+ * than this, but acquiring this height is considered sufficient for completion.
+ *
+ * @return target height in pixels.
*/
- default int getMaxHeight() {
- return getMaxTiles() * getTileHeight();
- }
+ int getTargetHeight();
/**
* @return the height of each image tile
@@ -234,11 +236,11 @@ public class ScrollCaptureClient {
private final int mTileWidth;
private Rect mRequestRect;
private boolean mStarted;
+ private final int mTargetHeight;
private ICancellationSignal mCancellationSignal;
private final Rect mWindowBounds;
private final Rect mBoundsInWindow;
- private final int mMaxTiles;
private Completer<Session> mStartCompleter;
private Completer<CaptureResult> mTileRequestCompleter;
@@ -256,7 +258,7 @@ public class ScrollCaptureClient {
mTileWidth = mBoundsInWindow.width();
mTileHeight = pxPerTile / mBoundsInWindow.width();
- mMaxTiles = (int) Math.ceil(maxPages * TILES_PER_PAGE);
+ mTargetHeight = (int) (mBoundsInWindow.height() * maxPages);
if (DEBUG_SCROLL) {
Log.d(TAG, "boundsInWindow: " + mBoundsInWindow);
@@ -285,7 +287,7 @@ public class ScrollCaptureClient {
private void start(Completer<Session> completer) {
mReader = ImageReader.newInstance(mTileWidth, mTileHeight, PixelFormat.RGBA_8888,
- mMaxTiles, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
+ MAX_TILES, HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE);
mStartCompleter = completer;
try {
mCancellationSignal = mConnection.startCapture(mReader.getSurface(), this);
@@ -410,8 +412,13 @@ public class ScrollCaptureClient {
}
@Override
+ public int getTargetHeight() {
+ return mTargetHeight;
+ }
+
+ @Override
public int getMaxTiles() {
- return mMaxTiles;
+ return MAX_TILES;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index bbcfdbd99bef..4c1f6a19b96c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -199,22 +199,20 @@ public class ScrollCaptureController {
Log.d(TAG, "onCaptureResult: " + result + " scrolling " + (mScrollingUp ? "UP" : "DOWN")
+ " finish on boundary: " + mFinishOnBoundary);
boolean emptyResult = result.captured.height() == 0;
- boolean partialResult = !emptyResult
- && result.captured.height() < result.requested.height();
- boolean finish = false;
if (emptyResult) {
// Potentially reached a vertical boundary. Extend in the other direction.
if (mFinishOnBoundary) {
- Log.d(TAG, "Partial/empty: finished!");
- finish = true;
+ Log.d(TAG, "Empty: finished!");
+ finishCapture();
+ return;
} else {
// We hit a boundary, clear the tiles, capture everything in the opposite direction,
// then finish.
mImageTileSet.clear();
mFinishOnBoundary = true;
mScrollingUp = !mScrollingUp;
- Log.d(TAG, "Partial/empty: cleared, switch direction to finish");
+ Log.d(TAG, "Empty: cleared, switch direction to finish");
}
} else {
// Got a non-empty result, but may already have enough bitmap data now
@@ -223,12 +221,14 @@ public class ScrollCaptureController {
Log.d(TAG, "Hit max tiles: finished");
// If we ever hit the max tiles, we've got enough bitmap data to finish
// (even if we weren't sure we'd finish on this pass).
- finish = true;
+ finishCapture();
+ return;
} else {
if (mScrollingUp && !mFinishOnBoundary) {
// During the initial scroll up, we only want to acquire the portion described
// by IDEAL_PORTION_ABOVE.
- if (expectedTiles >= mSession.getMaxTiles() * IDEAL_PORTION_ABOVE) {
+ if (mImageTileSet.getHeight() + result.captured.height()
+ >= mSession.getTargetHeight() * IDEAL_PORTION_ABOVE) {
Log.d(TAG, "Hit ideal portion above: clear and switch direction");
// We got enough above the start point, now see how far down it can go.
mImageTileSet.clear();
@@ -246,15 +246,15 @@ public class ScrollCaptureController {
+ " - " + mImageTileSet.getRight() + "," + mImageTileSet.getBottom()
+ " (" + mImageTileSet.getWidth() + "x" + mImageTileSet.getHeight() + ")");
-
- // Stop when "too tall"
- if (mImageTileSet.getHeight() > MAX_HEIGHT) {
- Log.d(TAG, "Max height reached.");
- finish = true;
+ Rect gapBounds = mImageTileSet.getGaps();
+ if (!gapBounds.isEmpty()) {
+ Log.d(TAG, "Found gaps in tileset: " + gapBounds + ", requesting " + gapBounds.top);
+ requestNextTile(gapBounds.top);
+ return;
}
- if (finish) {
- Log.d(TAG, "Stop.");
+ if (mImageTileSet.getHeight() >= mSession.getTargetHeight()) {
+ Log.d(TAG, "Target height reached.");
finishCapture();
return;
}
@@ -268,8 +268,8 @@ public class ScrollCaptureController {
: result.requested.bottom;
} else {
nextTop = (mScrollingUp)
- ? result.captured.top - mSession.getTileHeight()
- : result.captured.bottom;
+ ? mImageTileSet.getTop() - mSession.getTileHeight()
+ : mImageTileSet.getBottom();
}
requestNextTile(nextTop);
}
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
index 06c1c6f8cefa..e6d48676dc03 100644
--- a/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
@@ -218,7 +218,12 @@ class SensorUseStartedActivity @Inject constructor(
}
private fun disableSensorPrivacy() {
- sensorPrivacyController.setSensorBlocked(sensor, false)
+ if (sensor == ALL_SENSORS) {
+ sensorPrivacyController.setSensorBlocked(MICROPHONE, false)
+ sensorPrivacyController.setSensorBlocked(CAMERA, false)
+ } else {
+ sensorPrivacyController.setSensorBlocked(sensor, false)
+ }
unsuppressImmediately = true
setResult(RESULT_OK)
}
diff --git a/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
new file mode 100644
index 000000000000..9d101effa99f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/sensorprivacy/television/TvUnblockSensorActivity.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.sensorprivacy.television;
+
+import static android.hardware.SensorPrivacyManager.Sensors.CAMERA;
+import static android.hardware.SensorPrivacyManager.Sensors.MICROPHONE;
+
+import android.hardware.SensorPrivacyManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.IndividualSensorPrivacyController;
+import com.android.systemui.tv.TvBottomSheetActivity;
+
+import javax.inject.Inject;
+
+/**
+ * Bottom sheet that is shown when the camera/mic sensors are blocked by the global toggle and
+ * allows the user to re-enable them.
+ */
+public class TvUnblockSensorActivity extends TvBottomSheetActivity {
+
+ private static final String TAG = TvUnblockSensorActivity.class.getSimpleName();
+
+ private static final int ALL_SENSORS = Integer.MAX_VALUE;
+ private int mSensor = -1;
+
+ private final IndividualSensorPrivacyController mSensorPrivacyController;
+ private IndividualSensorPrivacyController.Callback mSensorPrivacyCallback;
+
+ @Inject
+ public TvUnblockSensorActivity(
+ IndividualSensorPrivacyController individualSensorPrivacyController) {
+ mSensorPrivacyController = individualSensorPrivacyController;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ boolean allSensors = getIntent().getBooleanExtra(SensorPrivacyManager.EXTRA_ALL_SENSORS,
+ false);
+ if (allSensors) {
+ mSensor = ALL_SENSORS;
+ } else {
+ mSensor = getIntent().getIntExtra(SensorPrivacyManager.EXTRA_SENSOR, -1);
+ }
+
+ if (mSensor == -1) {
+ Log.v(TAG, "Invalid extras");
+ finish();
+ return;
+ }
+
+ mSensorPrivacyCallback = (sensor, blocked) -> {
+ if (mSensor == ALL_SENSORS) {
+ if (!mSensorPrivacyController.isSensorBlocked(CAMERA)
+ && !mSensorPrivacyController.isSensorBlocked(MICROPHONE)) {
+ finish();
+ }
+ } else if (this.mSensor == sensor && !blocked) {
+ finish();
+ }
+ };
+
+ initUI();
+ }
+
+ private void initUI() {
+ TextView title = findViewById(R.id.bottom_sheet_title);
+ TextView content = findViewById(R.id.bottom_sheet_body);
+ ImageView icon = findViewById(R.id.bottom_sheet_icon);
+ // mic icon if both icons are shown
+ ImageView secondIcon = findViewById(R.id.bottom_sheet_second_icon);
+ Button unblockButton = findViewById(R.id.bottom_sheet_positive_button);
+ Button cancelButton = findViewById(R.id.bottom_sheet_negative_button);
+
+ switch (mSensor) {
+ case MICROPHONE:
+ title.setText(R.string.sensor_privacy_start_use_mic_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_mic_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ secondIcon.setVisibility(View.GONE);
+ break;
+ case CAMERA:
+ title.setText(R.string.sensor_privacy_start_use_camera_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_camera_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ secondIcon.setVisibility(View.GONE);
+ break;
+ case ALL_SENSORS:
+ default:
+ title.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_title);
+ content.setText(R.string.sensor_privacy_start_use_mic_camera_dialog_content);
+ icon.setImageResource(com.android.internal.R.drawable.perm_group_camera);
+ secondIcon.setImageResource(com.android.internal.R.drawable.perm_group_microphone);
+ break;
+ }
+ unblockButton.setText(
+ com.android.internal.R.string.sensor_privacy_start_use_dialog_turn_on_button);
+ unblockButton.setOnClickListener(v -> {
+ if (mSensor == ALL_SENSORS) {
+ mSensorPrivacyController.setSensorBlocked(CAMERA, false);
+ mSensorPrivacyController.setSensorBlocked(MICROPHONE, false);
+ } else {
+ mSensorPrivacyController.setSensorBlocked(mSensor, false);
+ }
+ });
+
+ cancelButton.setText(android.R.string.cancel);
+ cancelButton.setOnClickListener(v -> finish());
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mSensorPrivacyController.addCallback(mSensorPrivacyCallback);
+ }
+
+ @Override
+ public void onPause() {
+ mSensorPrivacyController.removeCallback(mSensorPrivacyCallback);
+ super.onPause();
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index ce796d9789cf..89dda9c52651 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -22,6 +22,7 @@ import android.app.ActivityManager
import android.content.res.Resources
import android.util.IndentingPrintWriter
import android.util.MathUtils
+import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
import androidx.annotation.VisibleForTesting
@@ -37,6 +38,7 @@ import javax.inject.Inject
@SysUISingleton
open class BlurUtils @Inject constructor(
@Main private val resources: Resources,
+ private val crossWindowBlurListeners: CrossWindowBlurListeners,
dumpManager: DumpManager
) : Dumpable {
val minBlurRadius = resources.getDimensionPixelSize(R.dimen.min_window_blur_radius)
@@ -97,7 +99,8 @@ open class BlurUtils @Inject constructor(
* @return {@code true} when supported.
*/
open fun supportsBlursOnWindows(): Boolean {
- return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx()
+ return CROSS_WINDOW_BLUR_SUPPORTED && ActivityManager.isHighEndGfx() &&
+ crossWindowBlurListeners.isCrossWindowBlurEnabled()
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 4a4e990728f3..6f4a73ec4516 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -18,6 +18,7 @@ import com.android.systemui.ExpandHelper
import com.android.systemui.Gefingerpoken
import com.android.systemui.R
import com.android.systemui.animation.Interpolators
+import com.android.systemui.biometrics.UdfpsKeyguardViewController
import com.android.systemui.classifier.Classifier
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
@@ -109,6 +110,11 @@ class LockscreenShadeTransitionController @Inject constructor(
private var nextHideKeyguardNeedsNoAnimation = false
/**
+ * The udfpsKeyguardViewController if it exists.
+ */
+ var udfpsKeyguardViewController: UdfpsKeyguardViewController? = null
+
+ /**
* The touch helper responsible for the drag down animation.
*/
val touchHelper = DragDownHelper(falsingManager, falsingCollector, this, context)
@@ -291,6 +297,7 @@ class LockscreenShadeTransitionController @Inject constructor(
// Fade out all content only visible on the lockscreen
notificationPanelController.setKeyguardOnlyContentAlpha(1.0f - scrimProgress)
depthController.transitionToFullShadeProgress = scrimProgress
+ udfpsKeyguardViewController?.setTransitionToFullShadeProgress(scrimProgress)
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 89005513d3d0..f03a9a8f3589 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -96,6 +96,15 @@ class NotificationShadeDepthController @Inject constructor(
var globalActionsSpring = DepthAnimation()
var showingHomeControls: Boolean = false
+ @VisibleForTesting
+ var brightnessMirrorSpring = DepthAnimation()
+ var brightnessMirrorVisible: Boolean = false
+ set(value) {
+ field = value
+ brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
+ else 0)
+ }
+
var qsPanelExpansion = 0f
set(value) {
if (field == value) return
@@ -186,13 +195,16 @@ class NotificationShadeDepthController @Inject constructor(
var blur = max(shadeRadius.toInt(), globalActionsRadius)
// Make blur be 0 if it is necessary to stop blur effect.
- if (scrimsVisible) {
+ if (scrimsVisible || !blurUtils.supportsBlursOnWindows()) {
blur = 0
}
+ val zoomOut = blurUtils.ratioOfBlurRadius(blur)
+
+ // Brightness slider removes blur, but doesn't affect zooms
+ blur = (blur * (1f - brightnessMirrorSpring.ratio)).toInt()
val opaque = scrimsVisible && !ignoreShadeBlurUntilHidden
blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
- val zoomOut = blurUtils.ratioOfBlurRadius(blur)
try {
if (root.isAttachedToWindow && root.windowToken != null) {
wallpaperManager.setWallpaperZoomOut(root.windowToken, zoomOut)
@@ -260,6 +272,7 @@ class NotificationShadeDepthController @Inject constructor(
shadeSpring.finishIfRunning()
shadeAnimation.finishIfRunning()
globalActionsSpring.finishIfRunning()
+ brightnessMirrorSpring.finishIfRunning()
}
}
@@ -425,6 +438,7 @@ class NotificationShadeDepthController @Inject constructor(
it.println("shadeRadius: ${shadeSpring.radius}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("globalActionsRadius: ${globalActionsSpring.radius}")
+ it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
it.println("ignoreShadeBlurUntilHidden: $ignoreShadeBlurUntilHidden")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
index f1479a149a41..f19cf5d8d9c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ExpandAnimationParameters.kt
@@ -22,11 +22,27 @@ class ExpandAnimationParameters(
)
var startTranslationZ = 0f
+
+ /**
+ * The top position of the notification at the start of the animation. This is needed in order
+ * to keep the notification at its place when launching a notification that is clipped rounded.
+ */
+ var startNotificationTop = 0f
var startClipTopAmount = 0
var parentStartClipTopAmount = 0
var progress = 0f
var linearProgress = 0f
+ /**
+ * The rounded top clipping at the beginning.
+ */
+ var startRoundedTopClipping = 0
+
+ /**
+ * The rounded top clipping of the parent notification at the start.
+ */
+ var parentStartRoundedTopClipping = 0
+
override val topChange: Int
get() {
// We need this compensation to ensure that the QS moves in sync.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
index c248670c48db..1bbef2562d21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
@@ -40,6 +40,11 @@ class NotificationLaunchAnimatorController(
private val headsUpManager: HeadsUpManagerPhone,
private val notification: ExpandableNotificationRow
) : ActivityLaunchAnimator.Controller {
+
+ companion object {
+ const val ANIMATION_DURATION_TOP_ROUNDING = 100L
+ }
+
private val notificationEntry = notification.entry
private val notificationKey = notificationEntry.sbn.key
@@ -54,18 +59,37 @@ class NotificationLaunchAnimatorController(
val height = max(0, notification.actualHeight - notification.clipBottomAmount)
val location = notification.locationOnScreen
+ val clipStartLocation = notificationListContainer.getTopClippingStartLocation()
+ val roundedTopClipping = Math.max(clipStartLocation - location[1], 0)
+ val windowTop = location[1] + roundedTopClipping
+ val topCornerRadius = if (roundedTopClipping > 0) {
+ // Because the rounded Rect clipping is complex, we start the top rounding at
+ // 0, which is pretty close to matching the real clipping.
+ // We'd have to clipOut the overlaid drawable too with the outer rounded rect in case
+ // if we'd like to have this perfect, but this is close enough.
+ 0f
+ } else {
+ notification.currentBackgroundRadiusTop
+ }
val params = ExpandAnimationParameters(
- top = location[1],
+ top = windowTop,
bottom = location[1] + height,
left = location[0],
right = location[0] + notification.width,
- topCornerRadius = notification.currentBackgroundRadiusTop,
+ topCornerRadius = topCornerRadius,
bottomCornerRadius = notification.currentBackgroundRadiusBottom
)
params.startTranslationZ = notification.translationZ
+ params.startNotificationTop = notification.translationY
+ params.startRoundedTopClipping = roundedTopClipping
params.startClipTopAmount = notification.clipTopAmount
if (notification.isChildInGroup) {
+ params.startNotificationTop += notification.notificationParent.translationY
+ val parentRoundedClip = Math.max(clipStartLocation
+ - notification.notificationParent.locationOnScreen[1], 0)
+ params.parentStartRoundedTopClipping = parentRoundedClip
+
val parentClip = notification.notificationParent.clipTopAmount
params.parentStartClipTopAmount = parentClip
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9d56e9b6f855..93166f39ad62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -35,6 +35,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -85,6 +86,7 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -133,7 +135,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mUpdateBackgroundOnUpdate;
private boolean mNotificationTranslationFinished = false;
- private ArrayList<MenuItem> mSnoozedMenuItems;
+ private boolean mIsSnoozed;
/**
* Listener for when {@link ExpandableNotificationRow} is laid out.
@@ -252,6 +254,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private OnExpandClickListener mOnExpandClickListener;
private View.OnClickListener mOnAppClickListener;
private View.OnClickListener mOnFeedbackClickListener;
+ private Path mExpandingClipPath;
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -836,6 +839,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
if (mExpandAnimationRunning && !isChildInGroup && mNotificationParent != null) {
mNotificationParent.setChildIsExpanding(false);
+ mNotificationParent.setExpandingClipPath(null);
mNotificationParent.setExtraWidthForClipping(0.0f);
mNotificationParent.setMinimumHeightForClipping(0);
}
@@ -1105,8 +1109,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
false /* force */, false /* removeControls */, -1 /* x */, -1 /* y */,
false /* resetMenu */);
mNotificationGutsManager.openGuts(this, 0, 0, item);
- mSnoozedMenuItems = mMenuRow.getMenuItems(mMenuRow.getMenuView().getContext());
- mMenuRow.resetMenu();
+ mIsSnoozed = true;
};
}
@@ -1821,10 +1824,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
void onGutsClosed() {
updateContentAccessibilityImportanceForGuts(true /* isEnabled */);
- if (mSnoozedMenuItems != null && mSnoozedMenuItems.size() > 0) {
- mMenuRow.setMenuItems(mSnoozedMenuItems);
- mSnoozedMenuItems = null;
- }
+ mIsSnoozed = false;
}
/**
@@ -2036,7 +2036,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
setTranslationZ(translationZ);
float extraWidthForClipping = params.getWidth() - getWidth();
setExtraWidthForClipping(extraWidthForClipping);
- int top = params.getTop();
+ int top;
+ if (params.getStartRoundedTopClipping() > 0) {
+ // If we were clipping initially, let's interpolate from the start position to the
+ // top. Otherwise, we just take the top directly.
+ float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ params.getProgress(0,
+ NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING));
+ float startTop = params.getStartNotificationTop();
+ top = (int) Math.min(MathUtils.lerp(startTop,
+ params.getTop(), expandProgress),
+ startTop);
+ } else {
+ top = params.getTop();
+ }
+ int actualHeight = params.getBottom() - top;
+ setActualHeight(actualHeight);
int startClipTopAmount = params.getStartClipTopAmount();
int clipTopAmount = (int) MathUtils.lerp(startClipTopAmount, 0, params.getProgress());
if (mNotificationParent != null) {
@@ -2065,13 +2080,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
setClipTopAmount(clipTopAmount);
}
setTranslationY(top);
- setActualHeight(params.getHeight());
mTopRoundnessDuringExpandAnimation = params.getTopCornerRadius() / mOutlineRadius;
mBottomRoundnessDuringExpandAnimation = params.getBottomCornerRadius() / mOutlineRadius;
invalidateOutline();
- mBackgroundNormal.setExpandAnimationParams(params);
+ mBackgroundNormal.setExpandAnimationSize(params.getWidth(), actualHeight);
}
public void setExpandAnimationRunning(boolean expandAnimationRunning) {
@@ -2468,7 +2482,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int intrinsicBefore = getIntrinsicHeight();
super.onLayout(changed, left, top, right, bottom);
- if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
+ if (intrinsicBefore != getIntrinsicHeight()
+ && (intrinsicBefore != 0 || getActualHeight() > 0)) {
notifyHeightChanged(true /* needsAnimation */);
}
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
@@ -2981,7 +2996,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
- if (canViewBeDismissed()) {
+ if (canViewBeDismissed() && !mIsSnoozed) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS);
}
boolean expandable = shouldShowPublic();
@@ -2997,7 +3012,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
isExpanded = isExpanded();
}
}
- if (expandable) {
+ if (expandable && !mIsSnoozed) {
if (isExpanded) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_COLLAPSE);
} else {
@@ -3085,6 +3100,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return super.childNeedsClipping(child);
}
+ /**
+ * Set a clip path to be set while expanding the notification. This is needed to nicely
+ * clip ourselves during the launch if we were clipped rounded in the beginning
+ */
+ public void setExpandingClipPath(Path path) {
+ mExpandingClipPath = path;
+ invalidate();
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ canvas.save();
+ if (mExpandingClipPath != null && (mExpandAnimationRunning || mChildIsExpanding)) {
+ // If we're launching a notification, let's clip if a clip rounded to the clipPath
+ canvas.clipPath(mExpandingClipPath);
+ }
+ super.dispatchDraw(canvas);
+ canvas.restore();
+ }
+
@Override
protected void applyRoundness() {
super.applyRoundness();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
index 754de580cd61..0f615aa9356f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBackgroundView.java
@@ -240,10 +240,10 @@ public class NotificationBackgroundView extends View {
invalidate();
}
- /** Set the current expand animation parameters. */
- public void setExpandAnimationParams(ExpandAnimationParameters params) {
- mActualHeight = params.getHeight();
- mActualWidth = params.getWidth();
+ /** Set the current expand animation size. */
+ public void setExpandAnimationSize(int actualWidth, int actualHeight) {
+ mActualHeight = actualHeight;
+ mActualWidth = actualWidth;
invalidate();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index 26606cda5582..197920f7be19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -72,8 +72,6 @@ public class AmbientState {
private boolean mUnlockHintRunning;
private boolean mQsCustomizerShowing;
private int mIntrinsicPadding;
- private int mExpandAnimationTopChange;
- private ExpandableNotificationRow mExpandingNotification;
private float mHideAmount;
private boolean mAppearing;
private float mPulseHeight = MAX_PULSE_HEIGHT;
@@ -518,22 +516,6 @@ public class AmbientState {
return isDozing() && !isPulsing(row.getEntry());
}
- public void setExpandAnimationTopChange(int expandAnimationTopChange) {
- mExpandAnimationTopChange = expandAnimationTopChange;
- }
-
- public void setExpandingNotification(ExpandableNotificationRow row) {
- mExpandingNotification = row;
- }
-
- public ExpandableNotificationRow getExpandingNotification() {
- return mExpandingNotification;
- }
-
- public int getExpandAnimationTopChange() {
- return mExpandAnimationTopChange;
- }
-
/**
* @return {@code true } when shade is completely hidden: in AOD, ambient display or when
* bypassing.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 2a2e733f78a1..7a5c18896e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -200,4 +200,11 @@ public interface NotificationListContainer extends
default void setWillExpand(boolean willExpand) {}
void setNotificationActivityStarter(NotificationActivityStarter notificationActivityStarter);
+
+ /**
+ * @return the start location where we start clipping notifications.
+ */
+ default int getTopClippingStartLocation() {
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f0201cb3482d..4e6d376919e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -77,6 +77,7 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.CommandQueue;
@@ -90,6 +91,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.ExpandAnimationParameters;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
@@ -111,6 +113,7 @@ import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.util.Assert;
+import com.android.systemui.util.leak.RotationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -138,6 +141,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// adb shell setprop persist.debug.nssl true && adb reboot
private static final boolean DEBUG = SystemProperties.getBoolean("persist.debug.nssl",
false /* default */);
+ // TODO(b/187291379) disable again before release
+ private static final boolean DEBUG_REMOVE_ANIMATION = SystemProperties.getBoolean(
+ "persist.debug.nssl.dismiss", true /* default */);
private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
private static final float RUBBER_BAND_FACTOR_AFTER_EXPAND = 0.15f;
@@ -421,6 +427,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
animateScroll();
};
private int mCornerRadius;
+ private int mMinimumPaddings;
+ private int mQsTilePadding;
+ private boolean mSkinnyNotifsInLandscape;
private int mSidePaddings;
private final Rect mBackgroundAnimationRect = new Rect();
private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
@@ -467,6 +476,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private final Path mRoundedClipPath = new Path();
/**
+ * The clip Path used to clip the launching notification. This may be different
+ * from the normal path, as the views launch animation could start clipped.
+ */
+ private final Path mLaunchedNotificationClipPath = new Path();
+
+ /**
* Should we use rounded rect clipping right now
*/
private boolean mShouldUseRoundedRectClipping = false;
@@ -489,6 +504,26 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private boolean mLaunchingNotification;
/**
+ * Does the launching notification need to be clipped
+ */
+ private boolean mLaunchingNotificationNeedsToBeClipped;
+
+ /**
+ * The current launch animation params when launching a notification
+ */
+ private ExpandAnimationParameters mLaunchAnimationParams;
+
+ /**
+ * Corner radii of the launched notification if it's clipped
+ */
+ private float[] mLaunchedNotificationRadii = new float[8];
+
+ /**
+ * The notification that is being launched currently.
+ */
+ private ExpandableNotificationRow mExpandingNotificationRow;
+
+ /**
* Do notifications dismiss with normal transitioning
*/
private boolean mDismissUsingRowTranslationX = true;
@@ -896,7 +931,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
R.dimen.min_top_overscroll_to_qs);
mStatusBarHeight = res.getDimensionPixelSize(R.dimen.status_bar_height);
mBottomMargin = res.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom);
- mSidePaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
+ mMinimumPaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
+ mQsTilePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal);
+ mSkinnyNotifsInLandscape = res.getBoolean(R.bool.config_skinnyNotifsInLandscape);
+ mSidePaddings = mMinimumPaddings; // Updated in onMeasure by updateSidePadding()
mMinInteractionHeight = res.getDimensionPixelSize(
R.dimen.notification_min_interaction_height);
mCornerRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
@@ -906,6 +944,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
com.android.internal.R.dimen.quick_qs_offset_height);
}
+ void updateSidePadding(int viewWidth) {
+ if (viewWidth == 0 || !mSkinnyNotifsInLandscape) {
+ mSidePaddings = mMinimumPaddings;
+ return;
+ }
+ // Portrait is easy, just use the dimen for paddings
+ if (RotationUtils.getRotation(mContext) == RotationUtils.ROTATION_NONE) {
+ mSidePaddings = mMinimumPaddings;
+ return;
+ }
+ final int innerWidth = viewWidth - mMinimumPaddings * 2;
+ final int qsTileWidth = (innerWidth - mQsTilePadding * 3) / 4;
+ mSidePaddings = mMinimumPaddings + qsTileWidth + mQsTilePadding;
+ }
+
void updateCornerRadius() {
int newRadius = getResources().getDimensionPixelSize(R.dimen.notification_corner_radius);
if (mCornerRadius != newRadius) {
@@ -966,6 +1019,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
+ updateSidePadding(width);
int childWidthSpec = MeasureSpec.makeMeasureSpec(width - mSidePaddings * 2,
MeasureSpec.getMode(widthMeasureSpec));
// Don't constrain the height of the children so we know how big they'd like to be
@@ -2117,7 +2171,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private void updateContentHeight() {
- final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mSidePaddings;
+ final float scrimTopPadding = mAmbientState.isOnKeyguard() ? 0 : mMinimumPaddings;
int height = (int) scrimTopPadding;
float previousPaddingRequest = mPaddingBetweenElements;
int numShownItems = 0;
@@ -2624,7 +2678,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
boolean generateRemoveAnimation(ExpandableView child) {
+ String key = "";
+ if (DEBUG_REMOVE_ANIMATION) {
+ if (child instanceof ExpandableNotificationRow) {
+ key = ((ExpandableNotificationRow) child).getEntry().getKey();
+ }
+ Log.d(TAG, "generateRemoveAnimation " + key);
+ }
if (removeRemovedChildFromHeadsUpChangeAnimations(child)) {
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "removedBecauseOfHeadsUp " + key);
+ }
mAddedHeadsUpChildren.remove(child);
return false;
}
@@ -2633,8 +2697,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mClearTransientViewsWhenFinished.add(child);
return true;
}
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "generateRemove " + key
+ + "\nmIsExpanded " + mIsExpanded
+ + "\nmAnimationsEnabled " + mAnimationsEnabled
+ + "\n!invisible group " + !isChildInInvisibleGroup(child));
+ }
if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
if (!mChildrenToAddAnimated.contains(child)) {
+ if (DEBUG_REMOVE_ANIMATION) {
+ Log.d(TAG, "needsAnimation = true " + key);
+ }
// Generate Animations
mChildrenToRemoveAnimated.add(child);
mNeedsAnimation = true;
@@ -2656,7 +2729,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
/**
* Remove a removed child view from the heads up animations if it was just added there
*
- * @return whether any child was removed from the list to animate
+ * @return whether any child was removed from the list to animate and the view was just added
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) {
@@ -2675,7 +2748,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
((ExpandableNotificationRow) child).setHeadsUpAnimatingAway(false);
}
mTmpList.clear();
- return hasAddEvent;
+ return hasAddEvent && mAddedHeadsUpChildren.contains(child);
}
// TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
@@ -2726,6 +2799,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* @return the amount of scrolling needed to start clipping notifications.
*/
private int getScrollAmountToScrollBoundary() {
+ if (mShouldUseSplitNotificationShade) {
+ return mSidePaddings;
+ }
return mTopPadding - mQsScrollBoundaryPosition;
}
@@ -2869,7 +2945,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
void setExpandingNotification(ExpandableNotificationRow row) {
- mAmbientState.setExpandingNotification(row);
+ if (mExpandingNotificationRow != null && row == null) {
+ // Let's unset the clip path being set during launch
+ mExpandingNotificationRow.setExpandingClipPath(null);
+ ExpandableNotificationRow parent = mExpandingNotificationRow.getNotificationParent();
+ if (parent != null) {
+ parent.setExpandingClipPath(null);
+ }
+ }
+ mExpandingNotificationRow = row;
+ updateLaunchedNotificationClipPath();
requestChildrenUpdate();
}
@@ -2879,10 +2964,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void applyExpandAnimationParams(ExpandAnimationParameters params) {
- mAmbientState.setExpandAnimationTopChange(params == null ? 0 : params.getTopChange());
-
- // Disable clipping for launches
+ // Modify the clipping for launching notifications
+ mLaunchAnimationParams = params;
setLaunchingNotification(params != null);
+ updateLaunchedNotificationClipPath();
requestChildrenUpdate();
}
@@ -5330,7 +5415,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return;
}
mLaunchingNotification = launching;
- updateUseRoundedRectClipping();
+ mLaunchingNotificationNeedsToBeClipped = mLaunchAnimationParams != null
+ && (mLaunchAnimationParams.getStartRoundedTopClipping() > 0
+ || mLaunchAnimationParams.getParentStartRoundedTopClipping() > 0);
+ if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification) {
+ mLaunchedNotificationClipPath.reset();
+ }
+ // When launching notifications, we're clipping the children individually instead of in
+ // dispatchDraw
+ invalidate();
}
/**
@@ -5340,22 +5433,97 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// We don't want to clip notifications when QS is expanded, because incoming heads up on
// the bottom would be clipped otherwise
boolean qsAllowsClipping = mQsExpansionFraction < 0.5f || mShouldUseSplitNotificationShade;
- boolean clip = !mLaunchingNotification && mIsExpanded && qsAllowsClipping;
+ boolean clip = mIsExpanded && qsAllowsClipping;
if (clip != mShouldUseRoundedRectClipping) {
mShouldUseRoundedRectClipping = clip;
invalidate();
}
}
+ /**
+ * Update the clip path for launched notifications in case they were originally clipped
+ */
+ private void updateLaunchedNotificationClipPath() {
+ if (!mLaunchingNotificationNeedsToBeClipped || !mLaunchingNotification
+ || mExpandingNotificationRow == null) {
+ return;
+ }
+ int left = Math.min(mLaunchAnimationParams.getLeft(), mRoundedRectClippingLeft);
+ int right = Math.max(mLaunchAnimationParams.getRight(), mRoundedRectClippingRight);
+ int bottom = Math.max(mLaunchAnimationParams.getBottom(), mRoundedRectClippingBottom);
+ float expandProgress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ mLaunchAnimationParams.getProgress(0,
+ NotificationLaunchAnimatorController.ANIMATION_DURATION_TOP_ROUNDING));
+ int top = (int) Math.min(MathUtils.lerp(mRoundedRectClippingTop,
+ mLaunchAnimationParams.getTop(), expandProgress),
+ mRoundedRectClippingTop);
+ float topRadius = mLaunchAnimationParams.getTopCornerRadius();
+ float bottomRadius = mLaunchAnimationParams.getBottomCornerRadius();
+ mLaunchedNotificationRadii[0] = topRadius;
+ mLaunchedNotificationRadii[1] = topRadius;
+ mLaunchedNotificationRadii[2] = topRadius;
+ mLaunchedNotificationRadii[3] = topRadius;
+ mLaunchedNotificationRadii[4] = bottomRadius;
+ mLaunchedNotificationRadii[5] = bottomRadius;
+ mLaunchedNotificationRadii[6] = bottomRadius;
+ mLaunchedNotificationRadii[7] = bottomRadius;
+ mLaunchedNotificationClipPath.reset();
+ mLaunchedNotificationClipPath.addRoundRect(left, top, right, bottom,
+ mLaunchedNotificationRadii, Path.Direction.CW);
+ // Offset into notification clip coordinates instead of parent ones.
+ // This is needed since the notification changes in translationZ, where clipping via
+ // canvas dispatching won't work.
+ ExpandableNotificationRow expandingRow = mExpandingNotificationRow;
+ if (expandingRow.getNotificationParent() != null) {
+ expandingRow = expandingRow.getNotificationParent();
+ }
+ mLaunchedNotificationClipPath.offset(
+ -expandingRow.getLeft() - expandingRow.getTranslationX(),
+ -expandingRow.getTop() - expandingRow.getTranslationY());
+ expandingRow.setExpandingClipPath(mLaunchedNotificationClipPath);
+ if (mShouldUseRoundedRectClipping) {
+ invalidate();
+ }
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mShouldUseRoundedRectClipping) {
+ if (mShouldUseRoundedRectClipping && !mLaunchingNotification) {
+ // When launching notifications, we're clipping the children individually instead of in
+ // dispatchDraw
// Let's clip rounded.
canvas.clipPath(mRoundedClipPath);
}
super.dispatchDraw(canvas);
}
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (mShouldUseRoundedRectClipping && mLaunchingNotification) {
+ // Let's clip children individually during notification launch
+ canvas.save();
+ ExpandableView expandableView = (ExpandableView) child;
+ Path clipPath;
+ if (expandableView.isExpandAnimationRunning()
+ || ((ExpandableView) child).hasExpandingChild()) {
+ // When launching the notification, it is not clipped by this layout, but by the
+ // view itself. This is because the view is Translating in Z, where this clipPath
+ // wouldn't apply.
+ clipPath = null;
+ } else {
+ clipPath = mRoundedClipPath;
+ }
+ if (clipPath != null) {
+ canvas.clipPath(clipPath);
+ }
+ boolean result = super.drawChild(canvas, child, drawingTime);
+ canvas.restore();
+ return result;
+ } else {
+ return super.drawChild(canvas, child, drawingTime);
+ }
+ }
+
/**
* Calculate the total translation needed when dismissing.
*/
@@ -5370,6 +5538,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
/**
+ * @return the start location where we start clipping notifications.
+ */
+ public int getTopClippingStartLocation() {
+ return mIsExpanded ? mQsScrollBoundaryPosition : 0;
+ }
+
+ /**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 495eda772219..e71f7dbb008b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1533,6 +1533,11 @@ public class NotificationStackScrollLayoutController {
}
@Override
+ public int getTopClippingStartLocation() {
+ return mView.getTopClippingStartLocation();
+ }
+
+ @Override
public View getContainerChildAt(int i) {
return mView.getContainerChildAt(i);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
index 54ef623e95ab..b148eeba2cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -27,6 +27,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
private val listeners: MutableList<ConfigurationController.ConfigurationListener> = ArrayList()
private val lastConfig = Configuration()
private var density: Int = 0
+ private var smallestScreenWidth: Int = 0
private var fontScale: Float = 0.toFloat()
private val inCarMode: Boolean
private var uiMode: Int = 0
@@ -38,6 +39,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
this.context = context
fontScale = currentConfig.fontScale
density = currentConfig.densityDpi
+ smallestScreenWidth = currentConfig.smallestScreenWidthDp
inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
Configuration.UI_MODE_TYPE_CAR
uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
@@ -72,6 +74,14 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController {
this.fontScale = fontScale
}
+ val smallestScreenWidth = newConfig.smallestScreenWidthDp
+ if (smallestScreenWidth != this.smallestScreenWidth) {
+ this.smallestScreenWidth = smallestScreenWidth
+ listeners.filterForEach({ this.listeners.contains(it) }) {
+ it.onSmallestScreenWidthChanged()
+ }
+ }
+
val localeList = newConfig.locales
if (localeList != this.localeList) {
this.localeList = localeList
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 3e4177d32a34..fa5011e8802f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -40,9 +40,9 @@ public class KeyguardClockPositionAlgorithm {
private static float CLOCK_HEIGHT_WEIGHT = 0.7f;
/**
- * Margin between the bottom of the clock and the notification shade.
+ * Margin between the bottom of the status view and the notification shade.
*/
- private int mClockNotificationsMargin;
+ private int mStatusViewBottomMargin;
/**
* Height of the parent view - display size in px.
@@ -153,8 +153,8 @@ public class KeyguardClockPositionAlgorithm {
* Refreshes the dimension values.
*/
public void loadDimens(Resources res) {
- mClockNotificationsMargin = res.getDimensionPixelSize(
- R.dimen.keyguard_clock_notifications_margin);
+ mStatusViewBottomMargin = res.getDimensionPixelSize(
+ R.dimen.keyguard_status_view_bottom_margin);
mContainerTopPadding =
res.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) / 2;
@@ -181,7 +181,7 @@ public class KeyguardClockPositionAlgorithm {
mNotificationStackHeight = notificationStackHeight;
mPanelExpansion = panelExpansion;
mHeight = parentHeight;
- mKeyguardStatusHeight = keyguardStatusHeight;
+ mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
mHasCustomClock = hasCustomClock;
@@ -221,40 +221,15 @@ public class KeyguardClockPositionAlgorithm {
public float getMinStackScrollerPadding() {
return mBypassEnabled ? mUnlockedStackScrollerPadding
- : mMinTopMargin + mKeyguardStatusHeight + mClockNotificationsMargin;
- }
-
- private int getMaxClockY() {
- return mHeight / 2 - mKeyguardStatusHeight - mClockNotificationsMargin;
+ : mMinTopMargin + mKeyguardStatusHeight;
}
private int getExpandedPreferredClockY() {
return mMinTopMargin + mUserSwitchHeight;
}
- /**
- * Vertically align the clock and the shade in the available space considering only
- * a percentage of the clock height defined by {@code CLOCK_HEIGHT_WEIGHT}.
- * @return Clock Y in pixels.
- */
- public int getExpandedClockPosition() {
- final int availableHeight = mMaxShadeBottom - mMinTopMargin;
- final int containerCenter = mMinTopMargin + availableHeight / 2;
-
- float y = containerCenter
- - (mKeyguardStatusHeight + mUserSwitchHeight) * CLOCK_HEIGHT_WEIGHT
- - mClockNotificationsMargin - mNotificationStackHeight / 2;
- if (y < mMinTopMargin) {
- y = mMinTopMargin;
- }
-
- // Don't allow the clock base to be under half of the screen
- final float maxClockY = getMaxClockY();
- if (y > maxClockY) {
- y = maxClockY;
- }
-
- return (int) y;
+ public int getLockscreenStatusViewHeight() {
+ return mKeyguardStatusHeight;
}
private int getClockY(float panelExpansion, float darkAmount) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 6b864c9c35df..41af80e02b5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -602,6 +602,10 @@ public class NotificationIconAreaController implements
updateAodIconColors();
}
+ public int getHeight() {
+ return mAodIcons == null ? 0 : mAodIcons.getHeight();
+ }
+
public void appearAodIcons() {
if (mAodIcons == null) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index aaddfca4b685..5d31786dd638 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -36,9 +36,11 @@ import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.Fragment;
import android.app.StatusBarManager;
+import android.content.ContentResolver;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
@@ -50,10 +52,12 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UserManager;
import android.os.VibrationEffect;
+import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
import android.view.LayoutInflater;
@@ -210,6 +214,8 @@ public class NotificationPanelViewController extends PanelViewController {
new MyOnHeadsUpChangedListener();
private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
+ private final SettingsChangeObserver mSettingsChangeObserver;
+
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
private final BiometricUnlockController mBiometricUnlockController;
@@ -594,6 +600,8 @@ public class NotificationPanelViewController extends PanelViewController {
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private final ContentResolver mContentResolver;
+
private final Executor mUiExecutor;
private final SecureSettings mSecureSettings;
@@ -635,6 +643,7 @@ public class NotificationPanelViewController extends PanelViewController {
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
+ @Main Handler handler,
LayoutInflater layoutInflater,
NotificationWakeUpCoordinator coordinator, PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
@@ -678,6 +687,7 @@ public class NotificationPanelViewController extends PanelViewController {
TapAgainViewController tapAgainViewController,
NavigationModeController navigationModeController,
FragmentService fragmentService,
+ ContentResolver contentResolver,
QuickAccessWalletController quickAccessWalletController,
@Main Executor uiExecutor,
SecureSettings secureSettings,
@@ -704,15 +714,12 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
mFeatureFlags = featureFlags;
+ mContentResolver = contentResolver;
mKeyguardQsUserSwitchComponentFactory = keyguardQsUserSwitchComponentFactory;
mKeyguardUserSwitcherComponentFactory = keyguardUserSwitcherComponentFactory;
mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
- mKeyguardUserSwitcherEnabled = mResources.getBoolean(
- com.android.internal.R.bool.config_keyguardUserSwitcher);
- mKeyguardQsUserSwitchEnabled =
- mKeyguardUserSwitcherEnabled && mResources.getBoolean(
- R.bool.config_keyguard_user_switch_opens_qs_details);
+ mSettingsChangeObserver = new SettingsChangeObserver(handler);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mView.setWillNotDraw(!DEBUG);
@@ -795,6 +802,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
mMaxKeyguardNotifications = resources.getInteger(R.integer.keyguard_max_notification_count);
+ updateUserSwitcherFlags();
onFinishInflate();
}
@@ -1034,6 +1042,10 @@ public class NotificationPanelViewController extends PanelViewController {
view = mLayoutInflater.inflate(layoutId, mView, false);
mView.addView(view, index);
} else {
+ // Add the stub back so we can re-inflate it again if necessary
+ ViewStub stub = new ViewStub(mView.getContext(), layoutId);
+ stub.setId(stubId);
+ mView.addView(stub, index);
view = null;
}
} else if (enabled) {
@@ -1061,6 +1073,7 @@ public class NotificationPanelViewController extends PanelViewController {
updateResources();
// Re-inflate the keyguard user switcher group.
+ updateUserSwitcherFlags();
boolean isUserSwitcherEnabled = mUserManager.isUserSwitcherEnabled();
boolean showQsUserSwitch = mKeyguardQsUserSwitchEnabled && isUserSwitcherEnabled;
boolean showKeyguardUserSwitcher =
@@ -1260,7 +1273,7 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
expandedFraction,
totalHeight,
- mKeyguardStatusViewController.getHeight(),
+ mKeyguardStatusViewController.getLockscreenHeight(),
userIconHeight,
userSwitcherPreferredY, hasCustomClock(),
hasVisibleNotifications, darkamount, mOverStretchAmount,
@@ -1443,7 +1456,6 @@ public class NotificationPanelViewController extends PanelViewController {
private void setQsExpansionEnabled() {
mQsExpansionEnabled = mQsExpansionEnabledPolicy && mQsExpansionEnabledAmbient;
- Log.d(TAG, "Set qsExpansionEnabled: " + mQsExpansionEnabled);
if (mQs == null) return;
mQs.setHeaderClickable(mQsExpansionEnabled);
}
@@ -2669,14 +2681,6 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected int getMaxPanelHeight() {
- if (mKeyguardBypassController.getBypassEnabled() && mBarState == KEYGUARD) {
- return getMaxPanelHeightBypass();
- } else {
- return getMaxPanelHeightNonBypass();
- }
- }
-
- private int getMaxPanelHeightNonBypass() {
int min = mStatusBarMinHeight;
if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
@@ -2701,16 +2705,6 @@ public class NotificationPanelViewController extends PanelViewController {
return maxHeight;
}
- private int getMaxPanelHeightBypass() {
- int position =
- mClockPositionAlgorithm.getExpandedClockPosition()
- + mKeyguardStatusViewController.getHeight();
- if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() != 0) {
- position += mShelfHeight / 2.0f + mDarkIconSize / 2.0f;
- }
- return position;
- }
-
public boolean isInSettings() {
return mQsExpanded;
}
@@ -2782,11 +2776,8 @@ public class NotificationPanelViewController extends PanelViewController {
maxHeight += mNotificationStackScrollLayoutController.getTopPaddingOverflow();
if (mBarState == KEYGUARD) {
- int
- minKeyguardPanelBottom =
- mClockPositionAlgorithm.getExpandedClockPosition()
- + mKeyguardStatusViewController.getHeight()
- + mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
+ int minKeyguardPanelBottom = mClockPositionAlgorithm.getLockscreenStatusViewHeight()
+ + mNotificationStackScrollLayoutController.getIntrinsicContentHeight();
return Math.max(maxHeight, minKeyguardPanelBottom);
} else {
return maxHeight;
@@ -3336,7 +3327,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()) {
// The expandedHeight is always the full panel Height when bypassing
- expandedHeight = getMaxPanelHeightNonBypass();
+ expandedHeight = getMaxPanelHeight();
}
mNotificationStackScrollLayoutController.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
@@ -3895,6 +3886,26 @@ public class NotificationPanelViewController extends PanelViewController {
return false;
}
+ private void updateUserSwitcherFlags() {
+ mKeyguardUserSwitcherEnabled = mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher);
+ mKeyguardQsUserSwitchEnabled =
+ mKeyguardUserSwitcherEnabled && mResources.getBoolean(
+ R.bool.config_keyguard_user_switch_opens_qs_details);
+ }
+
+ private void registerSettingsChangeListener() {
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.USER_SWITCHER_ENABLED),
+ /* notifyForDescendants */ false,
+ mSettingsChangeObserver
+ );
+ }
+
+ private void unregisterSettingsChangeListener() {
+ mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
+ }
+
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -4216,6 +4227,15 @@ public class NotificationPanelViewController extends PanelViewController {
}
@Override
+ public void onSmallestScreenWidthChanged() {
+ if (DEBUG) Log.d(TAG, "onSmallestScreenWidthChanged");
+
+ // Can affect multi-user switcher visibility as it depends on screen size by default:
+ // it is enabled only for devices with large screens (see config_keyguardUserSwitcher)
+ reInflateViews();
+ }
+
+ @Override
public void onOverlayChanged() {
if (DEBUG) Log.d(TAG, "onOverlayChanged");
reInflateViews();
@@ -4228,6 +4248,21 @@ public class NotificationPanelViewController extends PanelViewController {
}
}
+ private class SettingsChangeObserver extends ContentObserver {
+
+ SettingsChangeObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (DEBUG) Log.d(TAG, "onSettingsChanged");
+
+ // Can affect multi-user switcher visibility
+ reInflateViews();
+ }
+ }
+
private class StatusBarStateListener implements StateListener {
@Override
public void onStateChanged(int statusBarState) {
@@ -4343,10 +4378,12 @@ public class NotificationPanelViewController extends PanelViewController {
mConfigurationListener.onThemeChanged();
mFalsingManager.addTapListener(mFalsingTapListener);
mKeyguardIndicationController.init();
+ registerSettingsChangeListener();
}
@Override
public void onViewDetachedFromWindow(View v) {
+ unregisterSettingsChangeListener();
mFragmentService.getFragmentHostManager(mView)
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 1cb0be0efc90..ed8fb31aea32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -47,6 +47,8 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
private View mKeyguardStatusBar;
private boolean mQsExpanded;
private boolean mCustomizerAnimating;
+ private boolean mCustomizing;
+ private boolean mDetailShowing;
private int mBottomPadding;
private int mStackScrollerMargin;
@@ -140,7 +142,18 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
}
public void setCustomizerShowing(boolean isShowing) {
- if (isShowing) {
+ mCustomizing = isShowing;
+ updateBottomMargin();
+ mStackScroller.setQsCustomizerShowing(isShowing);
+ }
+
+ public void setDetailShowing(boolean isShowing) {
+ mDetailShowing = isShowing;
+ updateBottomMargin();
+ }
+
+ private void updateBottomMargin() {
+ if (mCustomizing || mDetailShowing) {
// Clear out bottom paddings/margins so the qs customization can be full height.
setPadding(0, 0, 0, 0);
setBottomMargin(mStackScroller, 0);
@@ -148,7 +161,6 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
setPadding(0, 0, 0, mBottomPadding);
setBottomMargin(mStackScroller, mStackScrollerMargin);
}
- mStackScroller.setQsCustomizerShowing(isShowing);
}
private void setBottomMargin(View v, int bottomMargin) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 7a1e5cf1770b..cfcea9684c3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -551,11 +551,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*/
public void setNotificationsBounds(float left, float top, float right, float bottom) {
if (mClipsQsScrim) {
- // notification scrim's rounded corners are anti-aliased, but clipping of the QS scrim
- // can't be and it's causing jagged corners. That's why notification scrim needs
- // to overlap QS scrim by one pixel - both vertically (top - 1) and
- // horizontally (left - 1 and right + 1), see: b/186644628
- mNotificationsScrim.setDrawableBounds(left - 1, top - 1, right + 1, bottom);
+ // notification scrim's rounded corners are anti-aliased, but clipping of the QS/behind
+ // scrim can't be and it's causing jagged corners. That's why notification scrim needs
+ // to overlap QS scrim by one pixel horizontally (left - 1 and right + 1)
+ // see: b/186644628
+ mNotificationsScrim.setDrawableBounds(left - 1, top, right + 1, bottom);
mScrimBehind.setBottomEdgePosition((int) top);
} else {
mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
@@ -1242,6 +1242,9 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
pw.println(mDefaultScrimAlpha);
pw.print(" mExpansionFraction=");
pw.println(mPanelExpansion);
+
+ pw.print(" mState.getMaxLightRevealScrimAlpha=");
+ pw.println(mState.getMaxLightRevealScrimAlpha());
}
public void setWallpaperSupportsAmbientMode(boolean wallpaperSupportsAmbientMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index e52e1fa5f39f..06811932ac0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -197,7 +197,7 @@ public enum ScrimState {
}
@Override
- public float getBehindAlpha() {
+ public float getMaxLightRevealScrimAlpha() {
return mWallpaperSupportsAmbientMode && !mHasBackdrop ? 0f : 1f;
}
@@ -220,18 +220,11 @@ public enum ScrimState {
mBlankScreen = mDisplayRequiresBlanking;
mAnimationDuration = mWakeLockScreenSensorActive
? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
-
- // Wake sensor will show the wallpaper, let's fade from black. Otherwise it will
- // feel like the screen is flashing if the wallpaper is light.
- if (mWakeLockScreenSensorActive && previousState == AOD) {
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
- }
}
-
@Override
- public float getBehindAlpha() {
+ public float getMaxLightRevealScrimAlpha() {
return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA
- : AOD.getBehindAlpha();
+ : AOD.getMaxLightRevealScrimAlpha();
}
},
@@ -351,6 +344,10 @@ public enum ScrimState {
return mBehindAlpha;
}
+ public float getMaxLightRevealScrimAlpha() {
+ return 1f;
+ }
+
public float getNotifAlpha() {
return mNotifAlpha;
}
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 5d2fe523c803..3f07785520cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1473,9 +1473,7 @@ public class StatusBar extends SystemUI implements DemoMode,
* @param why the reason for the wake up
*/
public void wakeUpIfDozing(long time, View where, String why) {
- if (mDozing && !(mKeyguardViewMediator.isAnimatingScreenOff()
- || mUnlockedScreenOffAnimationController
- .isScreenOffLightRevealAnimationPlaying())) {
+ if (mDozing && !mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()) {
mPowerManager.wakeUp(
time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why);
mWakeUpComingFromTouch = true;
@@ -4444,6 +4442,8 @@ public class StatusBar extends SystemUI implements DemoMode,
} else {
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
}
+ updateLightRevealScrimVisibility();
+
Trace.endSection();
}
@@ -4894,6 +4894,7 @@ public class StatusBar extends SystemUI implements DemoMode,
return;
}
+ mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
if (mFeatureFlags.useNewLockscreenAnimations()
&& (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
mLightRevealScrim.setVisibility(View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 52bf2d577776..9a04d39c4e9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -172,7 +172,8 @@ class UnlockedScreenOffAnimationController @Inject constructor(
// We currently draw both the light reveal scrim, and the AOD UI, in the shade. If it's
// already expanded and showing notifications/QS, the animation looks really messy. For now,
// disable it if the notification panel is expanded.
- if (statusBar.notificationPanelViewController.isFullyExpanded) {
+ if (!this::statusBar.isInitialized ||
+ statusBar.notificationPanelViewController.isFullyExpanded) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 399c8500ab48..a0edc7c494bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -74,11 +74,13 @@ public class BrightnessMirrorController
mBrightnessMirror.setVisibility(View.VISIBLE);
mVisibilityCallback.accept(true);
mNotificationPanel.setPanelAlpha(0, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(true);
}
public void hideMirror() {
mVisibilityCallback.accept(false);
mNotificationPanel.setPanelAlpha(255, true /* animate */);
+ mDepthController.setBrightnessMirrorVisible(false);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 0a6cf7be736f..c2bd87c6276f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -33,6 +33,7 @@ public interface ConfigurationController extends CallbackController<Configuratio
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
+ default void onSmallestScreenWidthChanged() {}
default void onOverlayChanged() {}
default void onUiModeChanged() {}
default void onThemeChanged() {}
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 ce080752b5cc..2ac5c1eeae8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -387,15 +387,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
int qsTypeIcon = 0;
IconState qsIcon = null;
CharSequence description = null;
- // Mobile icon will only be shown in the statusbar in 2 scenarios
- // 1. Mobile is the default network, and it is validated
- // 2. Mobile is the default network, it is not validated and there is no other
- // non-Carrier WiFi networks available.
- boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
- || (mCurrentState.inetCondition == 0
- && !mNetworkController.isNonCarrierWifiNetworkAvailable());
// Only send data sim callbacks to QS.
- if (mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons) {
+ if (mCurrentState.dataSim && mCurrentState.isDefault) {
qsTypeIcon =
(showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.qsDataType : 0;
qsIcon = new IconState(mCurrentState.enabled
@@ -408,7 +401,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
boolean activityOut = mCurrentState.dataConnected
&& !mCurrentState.carrierNetworkChangeMode
&& mCurrentState.activityOut;
- showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault && maybeShowIcons;
+ showDataIcon &= mCurrentState.dataSim && mCurrentState.isDefault;
boolean showTriangle = showDataIcon && !mCurrentState.airplaneMode;
int typeIcon = (showDataIcon || mConfig.alwaysShowDataRatIcon) ? icons.dataType : 0;
showDataIcon |= mCurrentState.roaming;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 753def0b0f1c..2406db3ee58f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -109,17 +109,10 @@ public class WifiSignalController extends
contentDescription += ("," + mContext.getString(R.string.data_connection_no_internet));
}
if (mProviderModel) {
- // WiFi icon will only be shown in the statusbar in 2 scenarios
- // 1. WiFi is the default network, and it is validated
- // 2. WiFi is the default network, it is not validated and there is no other
- // non-Carrier WiFi networks available.
- boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
- || (mCurrentState.inetCondition == 0
- && !mNetworkController.isNonCarrierWifiNetworkAvailable());
IconState statusIcon = new IconState(
- wifiVisible && maybeShowIcons, getCurrentIconId(), contentDescription);
+ wifiVisible, getCurrentIconId(), contentDescription);
IconState qsIcon = null;
- if ((mCurrentState.isDefault && maybeShowIcons) || (!mNetworkController.isRadioOn()
+ if (mCurrentState.isDefault || (!mNetworkController.isRadioOn()
&& !mNetworkController.isEthernetDefault())) {
qsIcon = new IconState(mCurrentState.connected,
mWifiTracker.isCaptivePortal ? R.drawable.ic_qs_wifi_disconnected
@@ -158,15 +151,8 @@ public class WifiSignalController extends
if (mCurrentState.inetCondition == 0) {
dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
}
- // Mobile icon will only be shown in the statusbar in 2 scenarios
- // 1. Mobile is the default network, and it is validated
- // 2. Mobile is the default network, it is not validated and there is no other
- // non-Carrier WiFi networks available.
- boolean maybeShowIcons = (mCurrentState.inetCondition == 1)
- || (mCurrentState.inetCondition == 0
- && !mNetworkController.isNonCarrierWifiNetworkAvailable());
boolean sbVisible = mCurrentState.enabled && mCurrentState.connected
- && maybeShowIcons && mCurrentState.isDefault;
+ && mCurrentState.isDefault;
IconState statusIcon =
new IconState(sbVisible, getCurrentIconIdForCarrierWifi(), contentDescription);
int typeIcon = sbVisible ? icons.dataType : 0;
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index ca1f55e95ff4..11ddbd045cd4 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -241,7 +241,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
@Override
public void onReceive(Context context, Intent intent) {
boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean userStarted = Intent.ACTION_USER_STARTED.equals(intent.getAction());
+ boolean userStarted = Intent.ACTION_USER_SWITCHED.equals(intent.getAction());
boolean isManagedProfile = mUserManager.isManagedProfile(
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
if (userStarted || newWorkProfile) {
@@ -288,7 +288,7 @@ public class ThemeOverlayController extends SystemUI implements Dumpable {
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index c5e35a497956..8b394bfe35b7 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -16,13 +16,18 @@
package com.android.systemui.toast;
+import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
+import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+
import android.animation.Animator;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Application;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -53,7 +58,7 @@ public class SystemUIToast implements ToastPlugin.Toast {
final ToastPlugin.Toast mPluginToast;
private final String mPackageName;
- private final int mUserId;
+ @UserIdInt private final int mUserId;
private final LayoutInflater mLayoutInflater;
final int mDefaultX = 0;
@@ -74,7 +79,7 @@ public class SystemUIToast implements ToastPlugin.Toast {
}
SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text,
- ToastPlugin.Toast pluginToast, String packageName, int userId,
+ ToastPlugin.Toast pluginToast, String packageName, @UserIdInt int userId,
int orientation) {
mLayoutInflater = layoutInflater;
mContext = context;
@@ -248,6 +253,15 @@ public class SystemUIToast implements ToastPlugin.Toast {
return null;
}
+ final Context userContext;
+ try {
+ userContext = context.createPackageContextAsUser("android",
+ 0, new UserHandle(userId));
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Could not create user package context");
+ return null;
+ }
+
final ApplicationsState appState =
ApplicationsState.getInstance((Application) context.getApplicationContext());
if (!appState.isUserAdded(userId)) {
@@ -255,9 +269,11 @@ public class SystemUIToast implements ToastPlugin.Toast {
+ "packageName=" + packageName);
return null;
}
+
+ final PackageManager packageManager = userContext.getPackageManager();
final AppEntry appEntry = appState.getEntry(packageName, userId);
if (appEntry == null || appEntry.info == null
- || !ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(appEntry)) {
+ || !showApplicationIcon(appEntry.info, packageManager)) {
return null;
}
@@ -265,7 +281,20 @@ public class SystemUIToast implements ToastPlugin.Toast {
UserHandle user = UserHandle.getUserHandleForUid(appInfo.uid);
IconFactory iconFactory = IconFactory.obtain(context);
Bitmap iconBmp = iconFactory.createBadgedIconBitmap(
- appInfo.loadUnbadgedIcon(context.getPackageManager()), user, true).icon;
+ appInfo.loadUnbadgedIcon(packageManager), user, true).icon;
return new BitmapDrawable(context.getResources(), iconBmp);
}
+
+ private static boolean showApplicationIcon(ApplicationInfo appInfo,
+ PackageManager packageManager) {
+ if (hasFlag(appInfo.flags, FLAG_UPDATED_SYSTEM_APP)) {
+ return packageManager.getLaunchIntentForPackage(appInfo.packageName)
+ != null;
+ }
+ return !hasFlag(appInfo.flags, FLAG_SYSTEM);
+ }
+
+ private static boolean hasFlag(int flags, int flag) {
+ return (flags & flag) != 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
new file mode 100644
index 000000000000..2b7a33260248
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvBottomSheetActivity.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tv;
+
+import android.app.Activity;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+import java.util.function.Consumer;
+
+/**
+ * Generic bottom sheet with up to two icons in the beginning and two buttons.
+ */
+public abstract class TvBottomSheetActivity extends Activity {
+
+ private static final String TAG = TvBottomSheetActivity.class.getSimpleName();
+ private Drawable mBackgroundWithBlur;
+ private Drawable mBackgroundWithoutBlur;
+
+ private final Consumer<Boolean> mBlurConsumer = this::onBlurChanged;
+
+ private void onBlurChanged(boolean enabled) {
+ Log.v(TAG, "blur enabled: " + enabled);
+ getWindow().setBackgroundDrawable(enabled ? mBackgroundWithBlur : mBackgroundWithoutBlur);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.tv_bottom_sheet);
+
+ overridePendingTransition(R.anim.tv_bottom_sheet_enter, 0);
+
+ mBackgroundWithBlur = getResources()
+ .getDrawable(R.drawable.bottom_sheet_background_with_blur);
+ mBackgroundWithoutBlur = getResources().getDrawable(R.drawable.bottom_sheet_background);
+
+ DisplayMetrics metrics = getResources().getDisplayMetrics();
+ int screenWidth = metrics.widthPixels;
+ int screenHeight = metrics.heightPixels;
+ int marginPx = getResources().getDimensionPixelSize(R.dimen.bottom_sheet_margin);
+
+ WindowManager.LayoutParams windowParams = getWindow().getAttributes();
+ windowParams.width = screenWidth - marginPx * 2;
+ windowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ windowParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+ windowParams.horizontalMargin = 0f;
+ windowParams.verticalMargin = (float) marginPx / screenHeight;
+ windowParams.format = PixelFormat.TRANSPARENT;
+ windowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+ windowParams.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ windowParams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+ getWindow().setAttributes(windowParams);
+ getWindow().setElevation(getWindow().getElevation() + 5);
+ getWindow().setBackgroundBlurRadius(getResources().getDimensionPixelSize(
+ R.dimen.bottom_sheet_background_blur_radius));
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getWindowManager().addCrossWindowBlurEnabledListener(mBlurConsumer);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ getWindowManager().removeCrossWindowBlurEnabledListener(mBlurConsumer);
+ super.onDetachedFromWindow();
+ }
+
+ @Override
+ public void finish() {
+ super.finish();
+ overridePendingTransition(0, R.anim.tv_bottom_sheet_exit);
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
index 5b50e897e254..62370313e5ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java
@@ -25,6 +25,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.content.Context;
+import android.content.ContextWrapper;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -39,6 +41,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,6 +61,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Rule
public MockitoRule mockito = MockitoJUnit.rule();
+ private Context mContextWrapper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private AccessibilityFloatingMenuController mController;
private AccessibilityButtonTargetsObserver mTargetsObserver;
@@ -66,6 +70,16 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardCallbackCaptor;
private KeyguardUpdateMonitorCallback mKeyguardCallback;
+ @Before
+ public void setUp() throws Exception {
+ mContextWrapper = new ContextWrapper(mContext) {
+ @Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ return getBaseContext();
+ }
+ };
+ }
+
@Test
public void initController_registerListeners() {
mController = setUpController();
@@ -105,7 +119,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
public void onKeyguardVisibilityChanged_showing_destroyWidget() {
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
@@ -131,7 +145,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserSwitching(fakeUserId);
@@ -144,7 +158,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
final int fakeUserId = 1;
enableAccessibilityFloatingMenuConfig();
mController = setUpController();
- mController.mFloatingMenu = new AccessibilityFloatingMenu(mContext);
+ mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper);
captureKeyguardUpdateMonitorCallback();
mKeyguardCallback.onUserUnlocked();
mKeyguardCallback.onKeyguardVisibilityChanged(true);
@@ -172,7 +186,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_floatingModeAndHasButtonTargets_showWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -184,7 +198,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_floatingModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
mController = setUpController();
@@ -195,7 +209,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_navBarModeAndHasButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -207,7 +221,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonModeChanged_navBarModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT);
mController = setUpController();
@@ -218,7 +232,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonTargetsChanged_floatingModeAndHasButtonTargets_showWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -230,7 +244,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonTargetsChanged_floatingModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
mController = setUpController();
@@ -242,7 +256,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonTargetsChanged_navBarModeAndHasButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
mController = setUpController();
@@ -254,7 +268,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
@Test
public void onAccessibilityButtonTargetsChanged_navBarModeAndNoButtonTargets_destroyWidget() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE,
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_CURRENT);
mController = setUpController();
@@ -269,15 +283,15 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase {
mModeObserver = spy(Dependency.get(AccessibilityButtonModeObserver.class));
mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
- return new AccessibilityFloatingMenuController(mContext, mTargetsObserver,
+ return new AccessibilityFloatingMenuController(mContextWrapper, mTargetsObserver,
mModeObserver, mKeyguardUpdateMonitor);
}
private void enableAccessibilityFloatingMenuConfig() {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU,
UserHandle.USER_CURRENT);
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.putStringForUser(mContextWrapper.getContentResolver(),
Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, TEST_A11Y_BTN_TARGETS,
UserHandle.USER_CURRENT);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 41f987727860..0c750a179358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -53,6 +53,7 @@ import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -117,6 +118,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Mock
private AccessibilityManager mAccessibilityManager;
@Mock
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock
private ScreenLifecycle mScreenLifecycle;
@Mock
private Vibrator mVibrator;
@@ -176,6 +179,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFalsingManager,
mPowerManager,
mAccessibilityManager,
+ mLockscreenShadeTransitionController,
mScreenLifecycle,
mVibrator,
Optional.of(mHbmProvider));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 5923de6719a8..f62587c6e87c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -35,6 +35,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -65,6 +66,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
+ private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock
private DumpManager mDumpManager;
@Mock
private DelayableExecutor mExecutor;
@@ -106,6 +109,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mExecutor,
mDumpManager,
mKeyguardViewMediator,
+ mLockscreenShadeTransitionController,
mUdfpsController);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index a11b9cf357a8..10997fab081f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -209,33 +209,14 @@ public class DozeTriggersTest extends SysuiTestCase {
// WHEN quick pick up is triggered
mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
- // THEN device goes into aod (shows clock with black background)
- verify(mMachine).requestState(DOZE_AOD);
+ // THEN request pulse
+ verify(mMachine).requestPulse(anyInt());
// THEN a log is taken that quick pick up was triggered
verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP);
}
@Test
- public void testQuickPickupTimeOutAfterExecutables() {
- // GIVEN quick pickup is triggered when device is in DOZE
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
- mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
- verify(mMachine).requestState(DOZE_AOD);
- verify(mMachine, never()).requestState(DozeMachine.State.DOZE);
-
- // WHEN next executable is run
- mExecutor.advanceClockToLast();
- mExecutor.runAllReady();
-
- // THEN device goes back into DOZE
- verify(mMachine).requestState(DozeMachine.State.DOZE);
-
- // THEN a log is taken that wake up timeout expired
- verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_WAKE_TIMEOUT);
- }
-
- @Test
public void testOnSensor_Fingerprint() {
// GIVEN dozing state
when(mMachine.getState()).thenReturn(DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
index 6e216428992f..2c686618a361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputAdapterTest.java
@@ -135,8 +135,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -154,8 +152,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineLayout.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.GONE);
@@ -176,9 +172,25 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mSeekBar.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
+ }
+
+ @Test
+ public void onBindViewHolder_bindConnectedDevice_withSelectableDevice_showAddIcon() {
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(mMediaDevices);
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
+ }
+
+ @Test
+ public void onBindViewHolder_bindConnectedDevice_withoutSelectableDevice_hideAddIcon() {
+ when(mMediaOutputController.getSelectableMediaDevice()).thenReturn(new ArrayList<>());
+ mMediaOutputAdapter.onBindViewHolder(mViewHolder, 0);
+
+ assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -245,8 +257,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mProgressBar.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTwoLineTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
}
@@ -263,8 +273,6 @@ public class MediaOutputAdapterTest extends SysuiTestCase {
assertThat(mViewHolder.mCheckBox.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mBottomDivider.getVisibility()).isEqualTo(View.GONE);
assertThat(mViewHolder.mTitleText.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mDivider.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mAddIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mTitleText.getText()).isEqualTo(TEST_DEVICE_NAME_1);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 589ae2e7f4f4..9bd07b88417d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -155,6 +155,7 @@ public class MediaOutputBaseDialogTest extends SysuiTestCase {
@Test
public void refresh_notInDragging_verifyUpdateAdapter() {
+ when(mMediaOutputBaseAdapter.getCurrentActivePosition()).thenReturn(-1);
when(mMediaOutputBaseAdapter.isDragging()).thenReturn(false);
mMediaOutputBaseDialogImpl.refresh();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index da63b8a3ca4b..4980f7406cee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -52,6 +52,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -108,7 +109,8 @@ public class NavigationBarControllerTest extends SysuiTestCase {
Dependency.get(Dependency.MAIN_HANDLER),
mock(UiEventLogger.class),
mock(NavigationBarOverlayController.class),
- mock(ConfigurationController.class)));
+ mock(ConfigurationController.class),
+ mock(UserTracker.class)));
initializeNavigationBars();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 4ec45b444c46..b1afeecf39f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -76,6 +76,7 @@ import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -276,7 +277,8 @@ public class NavigationBarTest extends SysuiTestCase {
mock(SystemActions.class),
mHandler,
mock(NavigationBarOverlayController.class),
- mUiEventLogger));
+ mUiEventLogger,
+ mock(UserTracker.class)));
}
private void processAllMessages() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
index 9c68f0d8a7ff..478658eb232d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSession.java
@@ -57,16 +57,19 @@ class FakeSession implements ScrollCaptureClient.Session {
private int mScrollDelta;
private int mPageHeight;
+ private int mTargetHeight;
FakeSession(int pageHeight, float maxPages, int tileHeight, int visiblePageTop,
- int visiblePageBottom, int availableTop, int availableBottom) {
+ int visiblePageBottom, int availableTop, int availableBottom,
+ int maxTiles) {
mPageHeight = pageHeight;
mTileHeight = tileHeight;
mAvailable = new Rect(0, availableTop, getPageWidth(), availableBottom);
mAvailableTop = new Rect(mAvailable);
mAvailableTop.inset(0, 0, 0, pageHeight);
mVisiblePage = new Rect(0, visiblePageTop, getPageWidth(), visiblePageBottom);
- mMaxTiles = (int) Math.ceil((pageHeight * maxPages) / mTileHeight);
+ mTargetHeight = (int) (pageHeight * maxPages);
+ mMaxTiles = maxTiles;
}
private static Image mockImage() {
@@ -158,6 +161,11 @@ class FakeSession implements ScrollCaptureClient.Session {
}
@Override
+ public int getTargetHeight() {
+ return mTargetHeight;
+ }
+
+ @Override
public int getTileHeight() {
return mTileHeight;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
index 2520af94380c..4c8a4b0f8f61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/FakeSessionTest.java
@@ -42,21 +42,6 @@ import org.junit.runner.RunWith;
@RunWith(AndroidTestingRunner.class)
public class FakeSessionTest extends SysuiTestCase {
@Test
- public void testMaxTiles() {
- FakeSession session = new FakeSession(
- /* pageHeight */ 100,
- /* maxPages */ 2.25f,
- /* tileHeight */ 10,
- /* visiblePageTop */ 0,
- /* visiblePageBottom */ 100,
- /* availableTop */ -250,
- /* availableBottom */ 250);
-
- // (pageHeight * maxPages) / tileHeight
- assertEquals("getMaxTiles()", 23, session.getMaxTiles());
- }
-
- @Test
public void testNonEmptyResult_hasImage() {
FakeSession session = new FakeSession(
/* pageHeight */ 100,
@@ -65,7 +50,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ 0,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertNotNull("result.image", result.image);
assertNotNull("result.image.getHardwareBuffer()", result.image.getHardwareBuffer());
@@ -80,7 +66,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ 0,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100));
assertNull("result.image", result.image);
}
@@ -94,7 +81,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertEquals("requested top", 0, result.requested.top);
@@ -113,7 +101,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(90));
assertEquals("requested top", 90, result.requested.top);
@@ -132,7 +121,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-100));
assertEquals("requested top", -100, result.requested.top);
@@ -151,7 +141,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -250,
- /* availableBottom */ 250);
+ /* availableBottom */ 250,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(150));
assertEquals("requested top", 150, result.requested.top);
@@ -170,7 +161,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-125));
assertEquals("requested top", -125, result.requested.top);
@@ -189,7 +181,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 100);
+ /* availableBottom */ 100,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(75));
assertEquals("requested top", 75, result.requested.top);
@@ -211,7 +204,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 25, // <<--
/* visiblePageBottom */ 100,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150));
assertEquals("requested top", -150, result.requested.top);
@@ -233,7 +227,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 75,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(50));
assertEquals("requested top", 50, result.requested.top);
@@ -252,7 +247,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 200);
+ /* availableBottom */ 200,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(-150));
assertTrue("captured rect is empty", result.captured.isEmpty());
}
@@ -266,7 +262,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 0,
/* visiblePageBottom */ 100,
/* availableTop */ -100,
- /* availableBottom */ 200);
+ /* availableBottom */ 200,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(200));
assertTrue("captured rect is empty", result.captured.isEmpty());
}
@@ -280,7 +277,8 @@ public class FakeSessionTest extends SysuiTestCase {
/* visiblePageTop */ 60, // <<---
/* visiblePageBottom */ 0,
/* availableTop */ -150,
- /* availableBottom */ 150);
+ /* availableBottom */ 150,
+ /* max Tiles */ 30);
ScrollCaptureClient.CaptureResult result = getUnchecked(session.requestTile(0));
assertEquals("requested top", 0, result.requested.top);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
index 5bab1bcddb6a..10c878a92745 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScrollCaptureControllerTest.java
@@ -92,14 +92,16 @@ public class ScrollCaptureControllerTest extends SysuiTestCase {
// Each tile is cropped to the visible page size, which is inset 5px from the TOP
// requested result
// 0, 50 5, 50
- // -45, 5 -40, 5 <-- clear previous / top
- // 5, 55 5, 55 (not cropped, target is positioned fully within visible range)
- // 55, 105 55, 105
- // 105, 155 105, 155
- // 155, 205 155, 205 <-- bottom
-
- assertEquals("top", -40, screenshot.getTop());
- assertEquals("bottom", 205, screenshot.getBottom());
+ // -45, 5 -40, 5
+ // -90, -40 -85, -40 <-- clear previous / top
+ // -40, 10 -40, 10 (not cropped, target is positioned fully within visible range)
+ // 10, 60 10, 60
+ // 60, 110 60, 110
+ // 110, 160 110, 160
+ // 160, 210 160, 210 <-- bottom
+
+ assertEquals("top", -85, screenshot.getTop());
+ assertEquals("bottom", 210, screenshot.getBottom());
}
@Test
@@ -119,13 +121,14 @@ public class ScrollCaptureControllerTest extends SysuiTestCase {
// requested result
// 0, 50 0, 50 // not cropped, positioned within visible range
// -50, 0 -50, 0 <-- clear previous/reverse
- // 0, 50 - 0, 45 // target now positioned at page bottom, bottom cropped
+ // 0, 50 0, 45 // target now positioned at page bottom, bottom cropped
// 45, 95, 45, 90
// 90, 140, 140, 135
- // 135, 185 185, 180 <-- bottom
+ // 135, 185 185, 180
+ // 180, 230 180, 225 <-- bottom
assertEquals("top", -50, screenshot.getTop());
- assertEquals("bottom", 180, screenshot.getBottom());
+ assertEquals("bottom", 225, screenshot.getBottom());
}
@Test
@@ -265,7 +268,8 @@ public class ScrollCaptureControllerTest extends SysuiTestCase {
mLocalVisibleBottom = mPageHeight;
}
Session session = new FakeSession(mPageHeight, mMaxPages, mTileHeight,
- mLocalVisibleTop, mLocalVisibleBottom, mAvailableTop, mAvailableBottom);
+ mLocalVisibleTop, mLocalVisibleBottom, mAvailableTop, mAvailableBottom,
+ /* maxTiles */ 30);
ScrollCaptureClient client = mock(ScrollCaptureClient.class);
when(client.start(/* response */ any(), /* maxPages */ anyFloat()))
.thenReturn(immediateFuture(session));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
index 7c7d2dc16c03..2b44d8bbd364 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar
import android.content.res.Resources
+import android.view.CrossWindowBlurListeners
import android.view.SurfaceControl
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
@@ -37,11 +38,13 @@ class BlurUtilsTest : SysuiTestCase() {
@Mock lateinit var resources: Resources
@Mock lateinit var dumpManager: DumpManager
@Mock lateinit var transaction: SurfaceControl.Transaction
+ @Mock lateinit var corssWindowBlurListeners: CrossWindowBlurListeners
lateinit var blurUtils: BlurUtils
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
+ `when`(corssWindowBlurListeners.isCrossWindowBlurEnabled).thenReturn(true)
blurUtils = TestableBlurUtils()
}
@@ -71,7 +74,7 @@ class BlurUtilsTest : SysuiTestCase() {
verify(transaction).apply()
}
- inner class TestableBlurUtils() : BlurUtils(resources, dumpManager) {
+ inner class TestableBlurUtils() : BlurUtils(resources, corssWindowBlurListeners, dumpManager) {
override fun supportsBlursOnWindows(): Boolean {
return true
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 61c3835a88d2..60b38892e776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -47,6 +47,7 @@ import org.mockito.Mockito.anyString
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.doThrow
import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@@ -71,6 +72,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
+ @Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@Mock private lateinit var dozeParameters: DozeParameters
@Captor private lateinit var scrimVisibilityCaptor: ArgumentCaptor<Consumer<Int>>
@@ -90,7 +92,11 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
(answer.arguments[0] as Float * maxBlur).toInt()
}
- `when`(blurUtils.minBlurRadius).thenReturn(0)
+ `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
+ answer.arguments[0] as Int / maxBlur.toFloat()
+ }
+ `when`(blurUtils.supportsBlursOnWindows()).thenReturn(true)
+ `when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
`when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
notificationShadeDepthController = NotificationShadeDepthController(
@@ -99,6 +105,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeWindowController, dozeParameters, dumpManager)
notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.shadeAnimation = shadeAnimation
+ notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.globalActionsSpring = globalActionsSpring
notificationShadeDepthController.root = root
@@ -191,6 +198,14 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
}
@Test
+ fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
+ reset(blurUtils)
+ notificationShadeDepthController.transitionToFullShadeProgress = 1f
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(blurUtils).applyBlur(any(), eq(0), eq(false))
+ }
+
+ @Test
fun updateGlobalDialogVisibility_animatesBlur() {
notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
verify(globalActionsSpring).animateTo(eq(maxBlur / 2), eq(root))
@@ -267,6 +282,32 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
}
@Test
+ fun brightnessMirrorVisible_whenVisible() {
+ notificationShadeDepthController.brightnessMirrorVisible = true
+ verify(brightnessSpring).animateTo(eq(maxBlur), any())
+ }
+
+ @Test
+ fun brightnessMirrorVisible_whenHidden() {
+ notificationShadeDepthController.brightnessMirrorVisible = false
+ verify(brightnessSpring).animateTo(eq(0), any())
+ }
+
+ @Test
+ fun brightnessMirror_hidesShadeBlur() {
+ // Brightness mirror is fully visible
+ `when`(brightnessSpring.ratio).thenReturn(1f)
+ // And shade is blurred
+ `when`(shadeSpring.radius).thenReturn(maxBlur)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur)
+
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(notificationShadeWindowController).setBackgroundBlurRadius(eq(0))
+ verify(wallpaperManager).setWallpaperZoomOut(any(), eq(1f))
+ verify(blurUtils).applyBlur(eq(viewRootImpl), eq(0), eq(false))
+ }
+
+ @Test
fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
`when`(shadeSpring.radius).thenReturn(0)
`when`(shadeAnimation.radius).thenReturn(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 2d51683c8ae5..2693b949f6ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -26,9 +26,12 @@ import static com.android.systemui.statusbar.notification.ViewGroupFadeHelper.re
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -37,9 +40,13 @@ import static org.mockito.Mockito.when;
import android.annotation.IdRes;
import android.app.ActivityManager;
+import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.hardware.biometrics.BiometricSourceType;
+import android.os.Handler;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.UserManager;
import android.testing.AndroidTestingRunner;
@@ -50,6 +57,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
+import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -60,6 +68,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
@@ -140,6 +149,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private KeyguardBottomAreaView mKeyguardBottomArea;
@Mock
private KeyguardBottomAreaView mQsFrame;
+ private KeyguardStatusView mKeyguardStatusView;
@Mock
private ViewGroup mBigClockContainer;
@Mock
@@ -153,6 +163,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private KeyguardStatusBarView mKeyguardStatusBar;
@Mock
+ private View mUserSwitcherView;
+ @Mock
+ private ViewStub mUserSwitcherStubView;
+ @Mock
private HeadsUpTouchHelper.Callback mHeadsUpCallback;
@Mock
private PanelBar mPanelBar;
@@ -204,7 +218,6 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private KeyguardClockSwitch mKeyguardClockSwitch;
private PanelViewController.TouchHandler mTouchHandler;
- @Mock
private ConfigurationController mConfigurationController;
@Mock
private MediaHierarchyManager mMediaHiearchyManager;
@@ -265,6 +278,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private SecureSettings mSecureSettings;
@Mock
+ private ContentResolver mContentResolver;
+ @Mock
private TapAgainViewController mTapAgainViewController;
@Mock
private KeyguardIndicationController mKeyguardIndicationController;
@@ -287,6 +302,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger);
+ mKeyguardStatusView = new KeyguardStatusView(mContext);
+ mKeyguardStatusView.setId(R.id.keyguard_status_view);
+
when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
when(mHeadsUpCallback.getContext()).thenReturn(mContext);
when(mView.getResources()).thenReturn(mResources);
@@ -301,6 +319,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
when(mResources.getDimensionPixelSize(R.dimen.notification_panel_width)).thenReturn(400);
when(mView.getContext()).thenReturn(getContext());
when(mView.findViewById(R.id.keyguard_header)).thenReturn(mKeyguardStatusBar);
+ when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(mUserSwitcherView);
+ when(mView.findViewById(R.id.keyguard_user_switcher_stub)).thenReturn(
+ mUserSwitcherStubView);
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
@@ -320,7 +341,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
- mNotificationContainerParent.addView(newViewWithId(R.id.keyguard_status_view));
+ mNotificationContainerParent.addView(mKeyguardStatusView);
when(mView.findViewById(R.id.notification_container_parent))
.thenReturn(mNotificationContainerParent);
when(mFragmentService.getFragmentHostManager(mView)).thenReturn(mFragmentHostManager);
@@ -348,6 +369,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mFalsingManager,
mLockscreenShadeTransitionController,
new FalsingCollectorFake());
+ mConfigurationController = new ConfigurationControllerImpl(mContext);
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
@@ -358,10 +380,16 @@ public class NotificationPanelViewTest extends SysuiTestCase {
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
+ .thenReturn(mKeyguardStatusView);
+ when(mLayoutInflater.inflate(eq(R.layout.keyguard_bottom_area), any(), anyBoolean()))
+ .thenReturn(mKeyguardBottomArea);
reset(mView);
+
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
+ new Handler(Looper.getMainLooper()),
mLayoutInflater,
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
@@ -395,6 +423,7 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mTapAgainViewController,
mNavigationModeController,
mFragmentService,
+ mContentResolver,
mQuickAccessWalletController,
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
@@ -549,6 +578,38 @@ public class NotificationPanelViewTest extends SysuiTestCase {
}
@Test
+ public void testDisableUserSwitcherAfterEnabling_returnsViewStubToTheViewHierarchy() {
+ givenViewAttached();
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
+ updateMultiUserSetting(true);
+ clearInvocations(mView);
+
+ updateMultiUserSetting(false);
+
+ ArgumentCaptor<View> captor = ArgumentCaptor.forClass(View.class);
+ verify(mView, atLeastOnce()).addView(captor.capture(), anyInt());
+ final View userSwitcherStub = CollectionUtils.find(captor.getAllValues(),
+ view -> view.getId() == R.id.keyguard_user_switcher_stub);
+ assertThat(userSwitcherStub).isNotNull();
+ assertThat(userSwitcherStub).isInstanceOf(ViewStub.class);
+ }
+
+ @Test
+ public void testChangeSmallestScreenWidthAndUserSwitchEnabled_inflatesUserSwitchView() {
+ givenViewAttached();
+ when(mView.findViewById(R.id.keyguard_user_switcher_view)).thenReturn(null);
+ updateSmallestScreenWidth(300);
+ when(mResources.getBoolean(
+ com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
+ when(mUserManager.isUserSwitcherEnabled()).thenReturn(true);
+
+ updateSmallestScreenWidth(800);
+
+ verify(mUserSwitcherStubView).inflate();
+ }
+
+ @Test
public void testSplitShadeLayout_isAlignedToGuideline() {
enableSplitShade();
@@ -682,6 +743,12 @@ public class NotificationPanelViewTest extends SysuiTestCase {
return mFalsingManager.getTapListeners().get(0);
}
+ private void givenViewAttached() {
+ for (View.OnAttachStateChangeListener listener : mOnAttachStateChangeListeners) {
+ listener.onViewAttachedToWindow(mView);
+ }
+ }
+
private View newViewWithId(int id) {
View view = new View(mContext);
view.setId(id);
@@ -704,6 +771,21 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mNotificationPanelViewController.updateResources();
}
+ private void updateMultiUserSetting(boolean enabled) {
+ when(mUserManager.isUserSwitcherEnabled()).thenReturn(enabled);
+ final ArgumentCaptor<ContentObserver> observerCaptor =
+ ArgumentCaptor.forClass(ContentObserver.class);
+ verify(mContentResolver)
+ .registerContentObserver(any(), anyBoolean(), observerCaptor.capture());
+ observerCaptor.getValue().onChange(/* selfChange */ false);
+ }
+
+ private void updateSmallestScreenWidth(int smallestScreenWidthDp) {
+ Configuration configuration = new Configuration();
+ configuration.smallestScreenWidthDp = smallestScreenWidthDp;
+ mConfigurationController.onConfigurationChanged(configuration);
+ }
+
private void onTouchEvent(MotionEvent ev) {
mTouchHandler.onTouch(mView, ev);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index e55361e750b1..678b193073c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -312,6 +312,8 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimBehind, true,
mScrimForBubble, false
));
+
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
}
@Test
@@ -321,8 +323,9 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, OPAQUE,
+ mScrimBehind, TRANSPARENT,
mNotificationsScrim, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
assertScrimTinted(Map.of(
mScrimInFront, true,
@@ -340,6 +343,7 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mScrimBehind, TRANSPARENT));
+ assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// Pulsing notification should conserve AOD wallpaper.
mScrimController.transitionTo(ScrimState.PULSING);
@@ -348,6 +352,7 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mScrimBehind, TRANSPARENT));
+ assertEquals(0f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
}
@Test
@@ -359,7 +364,8 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
assertScrimTinted(Map.of(
mScrimInFront, true,
@@ -378,7 +384,8 @@ public class ScrimControllerTest extends SysuiTestCase {
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
assertScrimTinted(Map.of(
mScrimInFront, true,
@@ -403,13 +410,15 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, SEMI_TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// ... and that if we set it while we're in AOD, it does take immediate effect.
mScrimController.setAodFrontScrimAlpha(1f);
assertScrimAlpha(Map.of(
mScrimInFront, OPAQUE,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// ... and make sure we recall the previous front scrim alpha even if we transition away
// for a bit.
@@ -418,7 +427,8 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, OPAQUE,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// ... and alpha updates should be completely ignored if always_on is off.
// Passing it forward would mess up the wake-up transition.
@@ -448,23 +458,28 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, OPAQUE,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// ... but will take effect after docked
when(mDockManager.isDocked()).thenReturn(true);
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setAodFrontScrimAlpha(0.5f);
mScrimController.transitionTo(ScrimState.AOD);
+ finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, SEMI_TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// ... and that if we set it while we're in AOD, it does take immediate effect after docked.
mScrimController.setAodFrontScrimAlpha(1f);
+ finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, OPAQUE,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// Reset value since enums are static.
mScrimController.setAodFrontScrimAlpha(0f);
@@ -480,7 +495,8 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
mScrimController.transitionTo(ScrimState.PULSING);
finishAnimationsImmediately();
@@ -489,7 +505,8 @@ public class ScrimControllerTest extends SysuiTestCase {
// Pulse callback should have been invoked
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
assertScrimTinted(Map.of(
mScrimInFront, true,
@@ -503,13 +520,16 @@ public class ScrimControllerTest extends SysuiTestCase {
// Front scrim should be semi-transparent
assertScrimAlpha(Map.of(
mScrimInFront, SEMI_TRANSPARENT,
- mScrimBehind, OPAQUE));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(1f, mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
mScrimController.setWakeLockScreenSensorActive(true);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, SEMI_TRANSPARENT,
- mScrimBehind, SEMI_TRANSPARENT));
+ mScrimBehind, TRANSPARENT));
+ assertEquals(ScrimController.WAKE_SENSOR_SCRIM_ALPHA,
+ mScrimController.getState().getMaxLightRevealScrimAlpha(), 0f);
// Reset value since enums are static.
mScrimController.setAodFrontScrimAlpha(0f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 521b958ab891..bd9d1a7fd657 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -238,9 +238,7 @@ public class NetworkControllerWifiTest extends NetworkControllerBaseTest {
mNetworkController.setNoNetworksAvailable(false);
setWifiStateForVcn(true, testSsid);
setWifiLevelForVcn(0);
- // Connected, but still not validated - does not show
- //verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
- verifyLastMobileDataIndicatorsForVcn(false, 0, 0, false);
+ verifyLastMobileDataIndicatorsForVcn(true, 0, TelephonyIcons.ICON_CWF, false);
mNetworkController.setNoNetworksAvailable(true);
for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 208790b24d8a..1a24c113a0df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -415,13 +415,6 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
}
@Test
- public void onUserSwitch_setsTheme() {
- mBroadcastReceiver.getValue().onReceive(null,
- new Intent(Intent.ACTION_USER_STARTED));
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
- }
-
- @Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
diff --git a/packages/services/CameraExtensionsProxy/AndroidManifest.xml b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
index e5f460e593b3..d35689413749 100644
--- a/packages/services/CameraExtensionsProxy/AndroidManifest.xml
+++ b/packages/services/CameraExtensionsProxy/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.camera">
+ package="com.android.cameraextensions">
<application
android:label="@string/app_name"
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 7b9ca2ddc345..69874f8a305a 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/camera/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.camera;
+package com.android.cameraextensions;
import android.app.Service;
import android.content.Context;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 241a0dbac758..f63198866b08 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -872,18 +872,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
"userId=" + userId);
}
+ final int resolvedUserId;
+ final List<AccessibilityServiceInfo> serviceInfos;
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
- final int resolvedUserId = mSecurityPolicy
+ resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+ serviceInfos = new ArrayList<>(
+ getUserStateLocked(resolvedUserId).mInstalledServices);
+ }
- if (Binder.getCallingPid() == OWN_PROCESS_ID) {
- return new ArrayList<>(getUserStateLocked(resolvedUserId).mInstalledServices);
+ if (Binder.getCallingPid() == OWN_PROCESS_ID) {
+ return serviceInfos;
+ }
+ final PackageManagerInternal pm = LocalServices.getService(
+ PackageManagerInternal.class);
+ final int callingUid = Binder.getCallingUid();
+ for (int i = serviceInfos.size() - 1; i >= 0; i--) {
+ final AccessibilityServiceInfo serviceInfo = serviceInfos.get(i);
+ if (pm.filterAppAccess(serviceInfo.getComponentName().getPackageName(), callingUid,
+ resolvedUserId)) {
+ serviceInfos.remove(i);
}
- return getUserStateLocked(resolvedUserId).mInstalledServices;
}
+ return serviceInfos;
}
@Override
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index acbf4875ae8d..5aec6aa99c12 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -409,6 +409,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
// If the set of providers has been modified, notify each active AppWidgetHost
scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
+ // Possibly notify any new components of widget id changes
+ mBackupRestoreController.widgetComponentsChanged(userId);
}
}
}
@@ -2471,8 +2473,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
@Override
- public void restoreStarting(int userId) {
- mBackupRestoreController.restoreStarting(userId);
+ public void systemRestoreStarting(int userId) {
+ mBackupRestoreController.systemRestoreStarting(userId);
}
@Override
@@ -2481,8 +2483,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
@Override
- public void restoreFinished(int userId) {
- mBackupRestoreController.restoreFinished(userId);
+ public void systemRestoreFinished(int userId) {
+ mBackupRestoreController.systemRestoreFinished(userId);
}
@SuppressWarnings("deprecation")
@@ -4272,6 +4274,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private final HashMap<Host, ArrayList<RestoreUpdateRecord>> mUpdatesByHost =
new HashMap<>();
+ @GuardedBy("mLock")
+ private boolean mHasSystemRestoreFinished;
+
public List<String> getWidgetParticipants(int userId) {
if (DEBUG) {
Slog.i(TAG, "Getting widget participants for user: " + userId);
@@ -4375,12 +4380,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
return stream.toByteArray();
}
- public void restoreStarting(int userId) {
+ public void systemRestoreStarting(int userId) {
if (DEBUG) {
- Slog.i(TAG, "Restore starting for user: " + userId);
+ Slog.i(TAG, "System restore starting for user: " + userId);
}
synchronized (mLock) {
+ mHasSystemRestoreFinished = false;
// We're starting a new "system" restore operation, so any widget restore
// state that we see from here on is intended to replace the current
// widget configuration of any/all of the affected apps.
@@ -4542,26 +4548,90 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
- // Called once following the conclusion of a restore operation. This is when we
+ // Called once following the conclusion of a system restore operation. This is when we
// send out updates to apps involved in widget-state restore telling them about
- // the new widget ID space.
- public void restoreFinished(int userId) {
+ // the new widget ID space. Apps that are not yet installed will be notifed when they are.
+ public void systemRestoreFinished(int userId) {
if (DEBUG) {
- Slog.i(TAG, "restoreFinished for " + userId);
+ Slog.i(TAG, "systemRestoreFinished for " + userId);
}
+ synchronized (mLock) {
+ mHasSystemRestoreFinished = true;
+ maybeSendWidgetRestoreBroadcastsLocked(userId);
+ }
+ }
- final UserHandle userHandle = new UserHandle(userId);
+ // Called when widget components (hosts or providers) are added or changed. If system
+ // restore has completed, we use this opportunity to tell the apps to update to the new
+ // widget ID space. If system restore is still in progress, we delay the updates until
+ // the end, to allow all participants to restore their state before updating widget IDs.
+ public void widgetComponentsChanged(int userId) {
synchronized (mLock) {
- // Build the providers' broadcasts and send them off
- Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
- = mUpdatesByProvider.entrySet();
- for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
- // For each provider there's a list of affected IDs
- Provider provider = e.getKey();
+ if (mHasSystemRestoreFinished) {
+ maybeSendWidgetRestoreBroadcastsLocked(userId);
+ }
+ }
+ }
+
+ // Called following the conclusion of a restore operation and when widget components
+ // are added or changed. This is when we send out updates to apps involved in widget-state
+ // restore telling them about the new widget ID space.
+ @GuardedBy("mLock")
+ private void maybeSendWidgetRestoreBroadcastsLocked(int userId) {
+ if (DEBUG) {
+ Slog.i(TAG, "maybeSendWidgetRestoreBroadcasts for " + userId);
+ }
+
+ final UserHandle userHandle = new UserHandle(userId);
+ // Build the providers' broadcasts and send them off
+ Set<Map.Entry<Provider, ArrayList<RestoreUpdateRecord>>> providerEntries
+ = mUpdatesByProvider.entrySet();
+ for (Map.Entry<Provider, ArrayList<RestoreUpdateRecord>> e : providerEntries) {
+ // For each provider there's a list of affected IDs
+ Provider provider = e.getKey();
+ if (provider.zombie) {
+ // Provider not installed, we can't send them broadcasts yet.
+ // We'll be called again when the provider is installed.
+ continue;
+ }
+ ArrayList<RestoreUpdateRecord> updates = e.getValue();
+ final int pending = countPendingUpdates(updates);
+ if (DEBUG) {
+ Slog.i(TAG, "Provider " + provider + " pending: " + pending);
+ }
+ if (pending > 0) {
+ int[] oldIds = new int[pending];
+ int[] newIds = new int[pending];
+ final int N = updates.size();
+ int nextPending = 0;
+ for (int i = 0; i < N; i++) {
+ RestoreUpdateRecord r = updates.get(i);
+ if (!r.notified) {
+ r.notified = true;
+ oldIds[nextPending] = r.oldId;
+ newIds[nextPending] = r.newId;
+ nextPending++;
+ if (DEBUG) {
+ Slog.i(TAG, " " + r.oldId + " => " + r.newId);
+ }
+ }
+ }
+ sendWidgetRestoreBroadcastLocked(
+ AppWidgetManager.ACTION_APPWIDGET_RESTORED,
+ provider, null, oldIds, newIds, userHandle);
+ }
+ }
+
+ // same thing per host
+ Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
+ = mUpdatesByHost.entrySet();
+ for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
+ Host host = e.getKey();
+ if (host.id.uid != UNKNOWN_UID) {
ArrayList<RestoreUpdateRecord> updates = e.getValue();
final int pending = countPendingUpdates(updates);
if (DEBUG) {
- Slog.i(TAG, "Provider " + provider + " pending: " + pending);
+ Slog.i(TAG, "Host " + host + " pending: " + pending);
}
if (pending > 0) {
int[] oldIds = new int[pending];
@@ -4581,43 +4651,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
sendWidgetRestoreBroadcastLocked(
- AppWidgetManager.ACTION_APPWIDGET_RESTORED,
- provider, null, oldIds, newIds, userHandle);
- }
- }
-
- // same thing per host
- Set<Map.Entry<Host, ArrayList<RestoreUpdateRecord>>> hostEntries
- = mUpdatesByHost.entrySet();
- for (Map.Entry<Host, ArrayList<RestoreUpdateRecord>> e : hostEntries) {
- Host host = e.getKey();
- if (host.id.uid != UNKNOWN_UID) {
- ArrayList<RestoreUpdateRecord> updates = e.getValue();
- final int pending = countPendingUpdates(updates);
- if (DEBUG) {
- Slog.i(TAG, "Host " + host + " pending: " + pending);
- }
- if (pending > 0) {
- int[] oldIds = new int[pending];
- int[] newIds = new int[pending];
- final int N = updates.size();
- int nextPending = 0;
- for (int i = 0; i < N; i++) {
- RestoreUpdateRecord r = updates.get(i);
- if (!r.notified) {
- r.notified = true;
- oldIds[nextPending] = r.oldId;
- newIds[nextPending] = r.newId;
- nextPending++;
- if (DEBUG) {
- Slog.i(TAG, " " + r.oldId + " => " + r.newId);
- }
- }
- }
- sendWidgetRestoreBroadcastLocked(
- AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
- null, host, oldIds, newIds, userHandle);
- }
+ AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED,
+ null, host, oldIds, newIds, userHandle);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 312cde6c5152..de5f47dd5dbb 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -662,6 +662,26 @@ public final class AutofillManagerService
return false;
}
+ /**
+ * Requests a count of saved passwords from the current service.
+ *
+ * @return {@code true} if the request succeeded
+ */
+ // Called by Shell command
+ boolean requestSavedPasswordCount(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
+ enforceCallingPermissionForManagement();
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ service.requestSavedPasswordCount(receiver);
+ return true;
+ } else if (sVerbose) {
+ Slog.v(TAG, "requestSavedPasswordCount(): no service for " + userId);
+ }
+ }
+ return false;
+ }
+
private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a80efc461176..5f2d4e82883c 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -76,6 +76,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.os.IResultReceiver;
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
@@ -1181,6 +1182,15 @@ final class AutofillManagerServiceImpl
}
@GuardedBy("mLock")
+ void requestSavedPasswordCount(IResultReceiver receiver) {
+ RemoteFillService remoteService =
+ new RemoteFillService(
+ getContext(), mInfo.getServiceInfo().getComponentName(), mUserId,
+ /* callbacks= */ null, mMaster.isInstantServiceAllowed());
+ remoteService.onSavedPasswordCountRequest(receiver);
+ }
+
+ @GuardedBy("mLock")
@Nullable RemoteAugmentedAutofillService getRemoteAugmentedAutofillServiceLocked() {
if (mRemoteAugmentedAutofillService == null) {
final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index 68e6290c987a..1eaa59a0871a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
+import static android.service.autofill.AutofillService.EXTRA_RESULT;
import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
@@ -89,6 +90,9 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
pw.println(" get bind-instant-service-allowed");
pw.println(" Gets whether binding to services provided by instant apps is allowed");
pw.println("");
+ pw.println(" get saved-password-count");
+ pw.println(" Gets the number of saved passwords in the current service.");
+ pw.println("");
pw.println(" set log_level [off | debug | verbose]");
pw.println(" Sets the Autofill log level.");
pw.println("");
@@ -145,6 +149,8 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
return getBindInstantService(pw);
case "default-augmented-service-enabled":
return getDefaultAugmentedServiceEnabled(pw);
+ case "saved-password-count":
+ return getSavedPasswordCount(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -342,6 +348,25 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand {
return 0;
}
+ private int getSavedPasswordCount(PrintWriter pw) {
+ final int userId = getNextIntArgRequired();
+ CountDownLatch latch = new CountDownLatch(1);
+ IResultReceiver resultReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) {
+ pw.println("resultCode=" + resultCode);
+ if (resultCode == 0 && resultData != null) {
+ pw.println("value=" + resultData.getInt(EXTRA_RESULT));
+ }
+ latch.countDown();
+ }
+ };
+ if (mService.requestSavedPasswordCount(userId, resultReceiver)) {
+ waitForLatch(pw, latch);
+ }
+ return 0;
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index b0755ac836e0..94872b09cd36 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -41,6 +41,7 @@ import android.util.Slog;
import com.android.internal.infra.AbstractRemoteService;
import com.android.internal.infra.ServiceConnector;
+import com.android.internal.os.IResultReceiver;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -225,6 +226,10 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> {
}));
}
+ void onSavedPasswordCountRequest(IResultReceiver receiver) {
+ run(service -> service.onSavedPasswordCountRequest(receiver));
+ }
+
public void destroy() {
unbind();
}
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 261ebe69a15e..f07bac8cd762 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -381,7 +381,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
- AppWidgetBackupBridge.restoreStarting(mUserId);
+ AppWidgetBackupBridge.systemRestoreStarting(mUserId);
}
try {
@@ -1133,8 +1133,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
restoreAgentTimeoutMillis);
}
- // Kick off any work that may be needed regarding app widget restores
- AppWidgetBackupBridge.restoreFinished(mUserId);
+ if (mIsSystemRestore) {
+ // Kick off any work that may be needed regarding app widget restores
+ AppWidgetBackupBridge.systemRestoreFinished(mUserId);
+ }
// If this was a full-system restore, record the ancestral
// dataset information
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 92996241a3a6..f7ddd2922b25 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1151,6 +1151,8 @@ public abstract class PackageManagerInternal implements PackageSettingsSnapshotP
/**
* Deletes the OAT artifacts of a package.
+ * @param packageName a specific package
+ * @return the number of freed bytes or -1 if there was an error in the process.
*/
- public abstract void deleteOatArtifactsOfPackage(String packageName);
+ public abstract long deleteOatArtifactsOfPackage(String packageName);
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 26ecee8f21ab..70176a0fefeb 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -38,6 +38,7 @@ import android.net.VpnManager;
import android.net.VpnService;
import android.net.util.NetdService;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.INetworkManagementService;
@@ -348,9 +349,17 @@ public class VpnManagerService extends IVpnManager.Stub {
/**
* Start legacy VPN, controlling native daemons as needed. Creates a
* secondary thread to perform connection work, returning quickly.
+ *
+ * Legacy VPN is deprecated starting from Android S. So this API shouldn't be called if the
+ * initial SDK version of device is Android S+. Otherwise, UnsupportedOperationException will be
+ * thrown.
*/
+ @SuppressWarnings("AndroidFrameworkCompatChange") // This is not an app-visible API.
@Override
public void startLegacyVpn(VpnProfile profile) {
+ if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.S) {
+ throw new UnsupportedOperationException("Legacy VPN is deprecated");
+ }
int user = UserHandle.getUserId(mDeps.getCallingUid());
// Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID),
// the code might not work well since getActiveNetwork might return null if the uid is
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2de091bb34bf..0c9772477734 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5684,6 +5684,16 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ try {
+ if (uid != 0) { // bypass the root
+ final String[] packageNames = getPackageManager().getPackagesForUid(uid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ // The uid is not existed or not visible to the caller.
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+ } catch (RemoteException e) {
+ }
return mUgmInternal.checkUriPermission(new GrantUri(userId, uri, modeFlags), uid, modeFlags)
? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 966e746b3c73..317b7757c239 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -203,8 +203,6 @@ public final class CachedAppOptimizer {
updateMinOomAdjThrottle();
} else if (KEY_COMPACT_THROTTLE_MAX_OOM_ADJ.equals(name)) {
updateMaxOomAdjThrottle();
- } else if (KEY_FREEZER_DEBOUNCE_TIMEOUT.equals(name)) {
- updateFreezerDebounceTimeout();
}
}
}
@@ -344,7 +342,6 @@ public final class CachedAppOptimizer {
updateUseFreezer();
updateMinOomAdjThrottle();
updateMaxOomAdjThrottle();
- updateFreezerDebounceTimeout();
}
}
@@ -656,6 +653,7 @@ public final class CachedAppOptimizer {
|| DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_USE_FREEZER, DEFAULT_USE_FREEZER)) {
mUseFreezer = isFreezerSupported();
+ updateFreezerDebounceTimeout();
}
final boolean useFreezer = mUseFreezer;
@@ -834,7 +832,8 @@ public final class CachedAppOptimizer {
@GuardedBy("mPhenotypeFlagLock")
private void updateFreezerDebounceTimeout() {
- mFreezerDebounceTimeout = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ mFreezerDebounceTimeout = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
KEY_FREEZER_DEBOUNCE_TIMEOUT, DEFAULT_FREEZER_DEBOUNCE_TIMEOUT);
if (mFreezerDebounceTimeout < 0) {
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index 697f6fa8eea8..ae1cd51e11f0 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -21,10 +21,18 @@ import static android.content.Intent.ACTION_PACKAGE_CHANGED;
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static com.android.server.wm.CompatModePackages.DOWNSCALED;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_40;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_45;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_50;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_55;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_60;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_65;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_70;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_75;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_80;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_85;
import static com.android.server.wm.CompatModePackages.DOWNSCALE_90;
import android.Manifest;
@@ -213,6 +221,39 @@ public final class GameManagerService extends IGameManagerService.Stub {
}
}
+ // Turn the raw string to the corresponding CompatChange id.
+ static long getCompatChangeId(String raw) {
+ switch (raw) {
+ case "0.3":
+ return DOWNSCALE_30;
+ case "0.35":
+ return DOWNSCALE_35;
+ case "0.4":
+ return DOWNSCALE_40;
+ case "0.45":
+ return DOWNSCALE_45;
+ case "0.5":
+ return DOWNSCALE_50;
+ case "0.55":
+ return DOWNSCALE_55;
+ case "0.6":
+ return DOWNSCALE_60;
+ case "0.65":
+ return DOWNSCALE_65;
+ case "0.7":
+ return DOWNSCALE_70;
+ case "0.75":
+ return DOWNSCALE_75;
+ case "0.8":
+ return DOWNSCALE_80;
+ case "0.85":
+ return DOWNSCALE_85;
+ case "0.9":
+ return DOWNSCALE_90;
+ }
+ return 0;
+ }
+
/**
* GamePackageConfiguration manages all game mode config details for its associated package.
*/
@@ -331,19 +372,7 @@ public final class GameManagerService extends IGameManagerService.Stub {
* Get the corresponding compat change id for the current scaling string.
*/
public long getCompatChangeId() {
- switch (mScaling) {
- case "0.5":
- return DOWNSCALE_50;
- case "0.6":
- return DOWNSCALE_60;
- case "0.7":
- return DOWNSCALE_70;
- case "0.8":
- return DOWNSCALE_80;
- case "0.9":
- return DOWNSCALE_90;
- }
- return 0;
+ return GameManagerService.getCompatChangeId(mScaling);
}
}
@@ -663,10 +692,18 @@ public final class GameManagerService extends IGameManagerService.Stub {
Slog.i(TAG, "Enabling downscale: " + scaleId + " for " + packageName);
final ArrayMap<Long, PackageOverride> overrides = new ArrayMap<>();
overrides.put(DOWNSCALED, COMPAT_ENABLED);
+ overrides.put(DOWNSCALE_30, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_35, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_40, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_45, COMPAT_DISABLED);
overrides.put(DOWNSCALE_50, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_55, COMPAT_DISABLED);
overrides.put(DOWNSCALE_60, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_65, COMPAT_DISABLED);
overrides.put(DOWNSCALE_70, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_75, COMPAT_DISABLED);
overrides.put(DOWNSCALE_80, COMPAT_DISABLED);
+ overrides.put(DOWNSCALE_85, COMPAT_DISABLED);
overrides.put(DOWNSCALE_90, COMPAT_DISABLED);
overrides.put(scaleId, COMPAT_ENABLED);
final CompatibilityOverrideConfig changeConfig = new CompatibilityOverrideConfig(
diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java
index 2074ffae1030..699f9e2d99f8 100644
--- a/services/core/java/com/android/server/app/GameManagerShellCommand.java
+++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java
@@ -16,6 +16,21 @@
package com.android.server.app;
+import static com.android.server.wm.CompatModePackages.DOWNSCALED;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_30;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_35;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_40;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_45;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_50;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_55;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_60;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_65;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_70;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_75;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_80;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_85;
+import static com.android.server.wm.CompatModePackages.DOWNSCALE_90;
+
import android.app.ActivityManager;
import android.app.GameManager;
import android.app.IGameManagerService;
@@ -27,7 +42,6 @@ import android.util.ArraySet;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.server.compat.PlatformCompat;
-import com.android.server.wm.CompatModePackages;
import java.io.PrintWriter;
import java.util.Set;
@@ -43,12 +57,21 @@ public class GameManagerShellCommand extends ShellCommand {
public GameManagerShellCommand() {}
private static final ArraySet<Long> DOWNSCALE_CHANGE_IDS = new ArraySet<>(new Long[]{
- CompatModePackages.DOWNSCALED,
- CompatModePackages.DOWNSCALE_90,
- CompatModePackages.DOWNSCALE_80,
- CompatModePackages.DOWNSCALE_70,
- CompatModePackages.DOWNSCALE_60,
- CompatModePackages.DOWNSCALE_50});
+ DOWNSCALED,
+ DOWNSCALE_90,
+ DOWNSCALE_85,
+ DOWNSCALE_80,
+ DOWNSCALE_75,
+ DOWNSCALE_70,
+ DOWNSCALE_65,
+ DOWNSCALE_60,
+ DOWNSCALE_55,
+ DOWNSCALE_50,
+ DOWNSCALE_45,
+ DOWNSCALE_40,
+ DOWNSCALE_35,
+ DOWNSCALE_30,
+ });
@Override
public int onCommand(String cmd) {
@@ -62,32 +85,9 @@ public class GameManagerShellCommand extends ShellCommand {
final String ratio = getNextArgRequired();
final String packageName = getNextArgRequired();
- final long changeId;
- switch (ratio) {
- case "0.5":
- changeId = CompatModePackages.DOWNSCALE_50;
- break;
- case "0.6":
- changeId = CompatModePackages.DOWNSCALE_60;
- break;
- case "0.7":
- changeId = CompatModePackages.DOWNSCALE_70;
- break;
- case "0.8":
- changeId = CompatModePackages.DOWNSCALE_80;
- break;
- case "0.9":
- changeId = CompatModePackages.DOWNSCALE_90;
- break;
- case "disable":
- changeId = 0;
- break;
- default:
- changeId = -1;
- pw.println("Invalid scaling ratio '" + ratio + "'");
- break;
- }
- if (changeId == -1) {
+ final long changeId = GameManagerService.getCompatChangeId(ratio);
+ if (changeId == 0 && !ratio.equals("disable")) {
+ pw.println("Invalid scaling ratio '" + ratio + "'");
break;
}
@@ -96,10 +96,10 @@ public class GameManagerShellCommand extends ShellCommand {
if (changeId == 0) {
disabled = DOWNSCALE_CHANGE_IDS;
} else {
- enabled.add(CompatModePackages.DOWNSCALED);
+ enabled.add(DOWNSCALED);
enabled.add(changeId);
disabled = DOWNSCALE_CHANGE_IDS.stream()
- .filter(it -> it != CompatModePackages.DOWNSCALED && it != changeId)
+ .filter(it -> it != DOWNSCALED && it != changeId)
.collect(Collectors.toSet());
}
@@ -204,7 +204,7 @@ public class GameManagerShellCommand extends ShellCommand {
pw.println("Game manager (game) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" downscale [0.5|0.6|0.7|0.8|0.9|disable] <PACKAGE_NAME>");
+ pw.println(" downscale [0.3|0.35|0.4|0.45|0.5|0.55|0.6|0.65|0.7|0.75|0.8|0.85|0.9|disable] <PACKAGE_NAME>");
pw.println(" Force app to run at the specified scaling ratio.");
pw.println(" mode [--user <USER_ID>] [1|2|3|standard|performance|battery] <PACKAGE_NAME>");
pw.println(" Force app to run in the specified game mode, if supported.");
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index 4cb2e9b5cb97..7f1402d83a0c 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -456,7 +456,9 @@ public final class AppHibernationService extends SystemService {
private void hibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackageGlobally");
if (mOatArtifactDeletionEnabled) {
- mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName);
+ state.savedByte = Math.max(
+ mPackageManagerInternal.deleteOatArtifactsOfPackage(packageName),
+ 0);
}
state.hibernated = true;
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -469,6 +471,7 @@ public final class AppHibernationService extends SystemService {
private void unhibernatePackageGlobally(@NonNull String packageName, GlobalLevelState state) {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackageGlobally");
state.hibernated = false;
+ state.savedByte = 0;
state.lastUnhibernatedMs = System.currentTimeMillis();
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -943,6 +946,9 @@ public final class AppHibernationService extends SystemService {
}
private final class StatsPullAtomCallbackImpl implements StatsPullAtomCallback {
+
+ private static final int MEGABYTE_IN_BYTES = 1000000;
+
@Override
public int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
if (!isAppHibernationEnabled()
@@ -969,12 +975,21 @@ public final class AppHibernationService extends SystemService {
break;
case FrameworkStatsLog.GLOBAL_HIBERNATED_APPS:
int hibernatedAppCount = 0;
+ long storage_saved_byte = 0;
synchronized (mLock) {
for (GlobalLevelState state : mGlobalHibernationStates.values()) {
- if (state.hibernated) hibernatedAppCount++;
+ if (state.hibernated) {
+ hibernatedAppCount++;
+ storage_saved_byte += state.savedByte;
+ }
}
}
- data.add(FrameworkStatsLog.buildStatsEvent(atomTag, hibernatedAppCount));
+ data.add(
+ FrameworkStatsLog.buildStatsEvent(
+ atomTag,
+ hibernatedAppCount,
+ storage_saved_byte / MEGABYTE_IN_BYTES)
+ );
break;
default:
return StatsManager.PULL_SKIP;
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
index 79e995b038fa..018d6023f083 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelHibernationProto.java
@@ -41,6 +41,7 @@ final class GlobalLevelHibernationProto implements ProtoReadWriter<List<GlobalLe
GlobalLevelState state = data.get(i);
stream.write(GlobalLevelHibernationStateProto.PACKAGE_NAME, state.packageName);
stream.write(GlobalLevelHibernationStateProto.HIBERNATED, state.hibernated);
+ stream.write(GlobalLevelHibernationStateProto.SAVED_BYTE, state.savedByte);
stream.end(token);
}
}
@@ -66,6 +67,10 @@ final class GlobalLevelHibernationProto implements ProtoReadWriter<List<GlobalLe
state.hibernated =
stream.readBoolean(GlobalLevelHibernationStateProto.HIBERNATED);
break;
+ case (int) GlobalLevelHibernationStateProto.SAVED_BYTE:
+ state.savedByte =
+ stream.readLong(GlobalLevelHibernationStateProto.SAVED_BYTE);
+ break;
default:
Slog.w(TAG, "Undefined field in proto: " + stream.getFieldNumber());
}
diff --git a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
index f4433a7fa5f6..104ecbc17d8a 100644
--- a/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
+++ b/services/core/java/com/android/server/apphibernation/GlobalLevelState.java
@@ -29,6 +29,8 @@ final class GlobalLevelState {
public String packageName;
public boolean hibernated;
+ // The number of saved bytes from the current hibernation. It will be 0 if not in hibernation.
+ public long savedByte;
@CurrentTimeMillisLong
public long lastUnhibernatedMs;
@@ -37,6 +39,7 @@ final class GlobalLevelState {
return "GlobalLevelState{"
+ "packageName='" + packageName + '\''
+ ", hibernated=" + hibernated + '\''
+ + ", savedByte=" + savedByte + '\''
+ ", lastUnhibernated=" + DATE_FORMAT.format(lastUnhibernatedMs)
+ '}';
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 99a33e4462e2..5ba75d3ac312 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,11 +19,13 @@ package com.android.server.appop;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
@@ -130,6 +132,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -200,8 +203,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
+import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class AppOpsService extends IAppOpsService.Stub {
@@ -2357,10 +2360,21 @@ public class AppOpsService extends IAppOpsService.Stub {
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -2377,10 +2391,21 @@ public class AppOpsService extends IAppOpsService.Stub {
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
+ Set<String> attributionChainExemptPackages = null;
+ if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+ attributionChainExemptPackages =
+ PermissionManager.getIndicatorExemptedPackages(mContext);
+ }
+
+ final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+ ? attributionChainExemptPackages.toArray(
+ new String[attributionChainExemptPackages.size()]) : null;
+
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
- filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
+ filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+ callback).recycleOnUse());
}
@Override
@@ -3838,7 +3863,8 @@ public class AppOpsService extends IAppOpsService.Stub {
final boolean isSelfBlame = Binder.getCallingUid() == proxiedUid;
final boolean isProxyTrusted = mContext.checkPermission(
Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
- == PackageManager.PERMISSION_GRANTED || isSelfBlame;
+ == PackageManager.PERMISSION_GRANTED || isSelfBlame
+ || attributionChainId != ATTRIBUTION_CHAIN_ID_NONE;
String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
proxiedPackageName);
@@ -5174,8 +5200,6 @@ public class AppOpsService extends IAppOpsService.Stub {
}
static class Shell extends ShellCommand {
- static final AtomicInteger sAttributionChainIds = new AtomicInteger(0);
-
final IAppOpsService mInterface;
final AppOpsService mInternal;
@@ -5645,8 +5669,7 @@ public class AppOpsService extends IAppOpsService.Stub {
shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
shell.packageName, shell.attributionTag, true, true,
"appops start shell command", true,
- AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR,
- shell.sAttributionChainIds.incrementAndGet());
+ AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR, ATTRIBUTION_CHAIN_ID_NONE);
} else {
return -1;
}
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 49469cc8a597..0439660f0c97 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -16,6 +16,9 @@
package com.android.server.appop;
+import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_ACCESSOR;
+import static android.app.AppOpsManager.ATTRIBUTION_FLAG_RECEIVER;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
@@ -58,7 +61,9 @@ import com.android.internal.util.XmlUtils;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.time.Duration;
@@ -69,6 +74,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
/**
* This class manages information about recent accesses to ops for permission usage timeline.
@@ -138,6 +145,7 @@ final class DiscreteRegistry {
private static final String TAG_HISTORY = "h";
private static final String ATTR_VERSION = "v";
+ private static final String ATTR_LARGEST_CHAIN_ID = "lc";
private static final int CURRENT_VERSION = 1;
private static final String TAG_UID = "u";
@@ -182,6 +190,16 @@ final class DiscreteRegistry {
DiscreteRegistry(Object inMemoryLock) {
mInMemoryLock = inMemoryLock;
+ synchronized (mOnDiskLock) {
+ mDiscreteAccessDir = new File(
+ new File(Environment.getDataSystemDirectory(), "appops"),
+ "discrete");
+ createDiscreteAccessDirLocked();
+ int largestChainId = readLargestChainIdFromDiskLocked();
+ synchronized (mInMemoryLock) {
+ mDiscreteOps = new DiscreteOps(largestChainId);
+ }
+ }
}
void systemReady() {
@@ -190,15 +208,6 @@ final class DiscreteRegistry {
setDiscreteHistoryParameters(p);
});
setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY));
- synchronized (mOnDiskLock) {
- synchronized (mInMemoryLock) {
- mDiscreteAccessDir = new File(
- new File(Environment.getDataSystemDirectory(), "appops"),
- "discrete");
- createDiscreteAccessDirLocked();
- mDiscreteOps = new DiscreteOps();
- }
- }
}
private void setDiscreteHistoryParameters(DeviceConfig.Properties p) {
@@ -251,7 +260,7 @@ final class DiscreteRegistry {
DiscreteOps discreteOps;
synchronized (mInMemoryLock) {
discreteOps = mDiscreteOps;
- mDiscreteOps = new DiscreteOps();
+ mDiscreteOps = new DiscreteOps(discreteOps.mChainIdOffset);
mCachedOps = null;
}
deleteOldDiscreteHistoryFilesLocked();
@@ -265,16 +274,109 @@ final class DiscreteRegistry {
long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ Set<String> attributionExemptPkgs) {
+ boolean assembleChains = attributionExemptPkgs != null;
DiscreteOps discreteOps = getAllDiscreteOps();
+ ArrayMap<Integer, AttributionChain> attributionChains = new ArrayMap<>();
+ if (assembleChains) {
+ attributionChains = createAttributionChains(discreteOps, attributionExemptPkgs);
+ }
beginTimeMillis = max(beginTimeMillis, Instant.now().minus(sDiscreteHistoryCutoff,
ChronoUnit.MILLIS).toEpochMilli());
discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
- discreteOps.applyToHistoricalOps(result);
+ opNamesFilter, attributionTagFilter, flagsFilter, attributionChains);
+ discreteOps.applyToHistoricalOps(result, attributionChains);
return;
}
+ private int readLargestChainIdFromDiskLocked() {
+ final File[] files = mDiscreteAccessDir.listFiles();
+ if (files != null && files.length > 0) {
+ File latestFile = null;
+ long latestFileTimestamp = 0;
+ for (File f : files) {
+ final String fileName = f.getName();
+ if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) {
+ continue;
+ }
+ long timestamp = Long.valueOf(fileName.substring(0,
+ fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length()));
+ if (latestFileTimestamp < timestamp) {
+ latestFile = f;
+ latestFileTimestamp = timestamp;
+ }
+ }
+ if (latestFile == null) {
+ return 0;
+ }
+ FileInputStream stream;
+ try {
+ stream = new FileInputStream(latestFile);
+ } catch (FileNotFoundException e) {
+ return 0;
+ }
+ try {
+ TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+ XmlUtils.beginDocument(parser, TAG_HISTORY);
+
+ final int largestChainId = parser.getAttributeInt(null, ATTR_LARGEST_CHAIN_ID, 0);
+ return largestChainId;
+ } catch (Throwable t) {
+ return 0;
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ private ArrayMap<Integer, AttributionChain> createAttributionChains(
+ DiscreteOps discreteOps, Set<String> attributionExemptPkgs) {
+ ArrayMap<Integer, AttributionChain> chains = new ArrayMap<>();
+ int nUids = discreteOps.mUids.size();
+ for (int uidNum = 0; uidNum < nUids; uidNum++) {
+ ArrayMap<String, DiscretePackageOps> pkgs = discreteOps.mUids.valueAt(uidNum).mPackages;
+ int uid = discreteOps.mUids.keyAt(uidNum);
+ int nPackages = pkgs.size();
+ for (int pkgNum = 0; pkgNum < nPackages; pkgNum++) {
+ ArrayMap<Integer, DiscreteOp> ops = pkgs.valueAt(pkgNum).mPackageOps;
+ String pkg = pkgs.keyAt(pkgNum);
+ int nOps = ops.size();
+ for (int opNum = 0; opNum < nOps; opNum++) {
+ ArrayMap<String, List<DiscreteOpEvent>> attrOps =
+ ops.valueAt(opNum).mAttributedOps;
+ int op = ops.keyAt(opNum);
+ int nAttrOps = attrOps.size();
+ for (int attrOpNum = 0; attrOpNum < nAttrOps; attrOpNum++) {
+ List<DiscreteOpEvent> opEvents = attrOps.valueAt(attrOpNum);
+ String attributionTag = attrOps.keyAt(attrOpNum);
+ int nOpEvents = opEvents.size();
+ for (int opEventNum = 0; opEventNum < nOpEvents; opEventNum++) {
+ DiscreteOpEvent event = opEvents.get(opEventNum);
+ if (event == null
+ || event.mAttributionChainId == ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
+
+ if (!chains.containsKey(event.mAttributionChainId)) {
+ chains.put(event.mAttributionChainId,
+ new AttributionChain(attributionExemptPkgs));
+ }
+ chains.get(event.mAttributionChainId)
+ .addEvent(pkg, uid, attributionTag, op, event);
+ }
+ }
+ }
+ }
+ }
+ return chains;
+ }
+
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
synchronized (mOnDiskLock) {
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
@@ -301,7 +403,7 @@ final class DiscreteRegistry {
void clearHistory() {
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
- mDiscreteOps = new DiscreteOps();
+ mDiscreteOps = new DiscreteOps(0);
}
clearOnDiskHistoryLocked();
}
@@ -340,7 +442,11 @@ final class DiscreteRegistry {
String[] opNamesFilter = dumpOp == OP_NONE ? null
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
- opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
+ opNamesFilter, attributionTagFilter, OP_FLAGS_ALL, new ArrayMap<>());
+ pw.print(prefix);
+ pw.print("Largest chain id: ");
+ pw.print(mDiscreteOps.mLargestChainId);
+ pw.println();
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
}
@@ -351,14 +457,14 @@ final class DiscreteRegistry {
}
private DiscreteOps getAllDiscreteOps() {
- DiscreteOps discreteOps = new DiscreteOps();
+ DiscreteOps discreteOps = new DiscreteOps(0);
synchronized (mOnDiskLock) {
synchronized (mInMemoryLock) {
discreteOps.merge(mDiscreteOps);
}
if (mCachedOps == null) {
- mCachedOps = new DiscreteOps();
+ mCachedOps = new DiscreteOps(0);
readDiscreteOpsFromDisk(mCachedOps);
}
discreteOps.merge(mCachedOps);
@@ -366,11 +472,143 @@ final class DiscreteRegistry {
}
}
+ /**
+ * Represents a chain of usages, each attributing its usage to the one before it
+ */
+ private static final class AttributionChain {
+ private static final class OpEvent {
+ String mPkgName;
+ int mUid;
+ String mAttributionTag;
+ int mOpCode;
+ DiscreteOpEvent mOpEvent;
+
+ OpEvent(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ mPkgName = pkgName;
+ mUid = uid;
+ mAttributionTag = attributionTag;
+ mOpCode = opCode;
+ mOpEvent = event;
+ }
+
+ public boolean matches(String pkgName, int uid, String attributionTag, int opCode,
+ DiscreteOpEvent event) {
+ return Objects.equals(pkgName, mPkgName) && mUid == uid
+ && Objects.equals(attributionTag, mAttributionTag) && mOpCode == opCode
+ && mOpEvent.mAttributionChainId == event.mAttributionChainId
+ && mOpEvent.mAttributionFlags == event.mAttributionFlags
+ && mOpEvent.mNoteTime == event.mNoteTime;
+ }
+
+ public boolean packageOpEquals(OpEvent other) {
+ return Objects.equals(other.mPkgName, mPkgName) && other.mUid == mUid
+ && Objects.equals(other.mAttributionTag, mAttributionTag)
+ && mOpCode == other.mOpCode;
+ }
+
+ public boolean equalsExceptDuration(OpEvent other) {
+ if (other.mOpEvent.mNoteDuration == mOpEvent.mNoteDuration) {
+ return false;
+ }
+ return packageOpEquals(other) && mOpEvent.equalsExceptDuration(other.mOpEvent);
+ }
+ }
+
+ ArrayList<OpEvent> mChain = new ArrayList<>();
+ Set<String> mExemptPkgs;
+ OpEvent mStartEvent = null;
+ OpEvent mLastVisibleEvent = null;
+
+ AttributionChain(Set<String> exemptPkgs) {
+ mExemptPkgs = exemptPkgs;
+ }
+
+ boolean isComplete() {
+ return !mChain.isEmpty() && getStart() != null && isEnd(mChain.get(mChain.size() - 1));
+ }
+
+ boolean isStart(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ if (mStartEvent == null || opEvent == null) {
+ return false;
+ }
+ return mStartEvent.matches(pkgName, uid, attributionTag, op, opEvent);
+ }
+
+ private OpEvent getStart() {
+ return mChain.isEmpty() || !isStart(mChain.get(0)) ? null : mChain.get(0);
+ }
+
+ private OpEvent getLastVisible() {
+ // Search all nodes but the first one, which is the start node
+ for (int i = mChain.size() - 1; i > 0; i--) {
+ OpEvent event = mChain.get(i);
+ if (!mExemptPkgs.contains(event.mPkgName)) {
+ return event;
+ }
+ }
+ return null;
+ }
+
+ void addEvent(String pkgName, int uid, String attributionTag, int op,
+ DiscreteOpEvent opEvent) {
+ OpEvent event = new OpEvent(pkgName, uid, attributionTag, op, opEvent);
+
+ // check if we have a matching event, without duration, replacing duration otherwise
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent item = mChain.get(i);
+ if (item.equalsExceptDuration(event)) {
+ if (event.mOpEvent.mNoteDuration != -1) {
+ item.mOpEvent = event.mOpEvent;
+ }
+ return;
+ }
+ }
+
+ if (mChain.isEmpty() || isEnd(event)) {
+ mChain.add(event);
+ } else if (isStart(event)) {
+ mChain.add(0, event);
+
+ } else {
+ for (int i = 0; i < mChain.size(); i++) {
+ OpEvent currEvent = mChain.get(i);
+ if ((!isStart(currEvent)
+ && currEvent.mOpEvent.mNoteTime > event.mOpEvent.mNoteTime)
+ || i == mChain.size() - 1 && isEnd(currEvent)) {
+ mChain.add(i, event);
+ break;
+ } else if (i == mChain.size() - 1) {
+ mChain.add(event);
+ break;
+ }
+ }
+ }
+ mStartEvent = isComplete() ? getStart() : null;
+ mLastVisibleEvent = isComplete() ? getLastVisible() : null;
+ }
+
+ private boolean isEnd(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_ACCESSOR) != 0;
+ }
+
+ private boolean isStart(OpEvent event) {
+ return event != null
+ && (event.mOpEvent.mAttributionFlags & ATTRIBUTION_FLAG_RECEIVER) != 0;
+ }
+ }
+
private final class DiscreteOps {
ArrayMap<Integer, DiscreteUidOps> mUids;
+ int mChainIdOffset;
+ int mLargestChainId;
- DiscreteOps() {
+ DiscreteOps(int chainIdOffset) {
mUids = new ArrayMap<>();
+ mChainIdOffset = chainIdOffset;
+ mLargestChainId = chainIdOffset;
}
boolean isEmpty() {
@@ -378,6 +616,7 @@ final class DiscreteRegistry {
}
void merge(DiscreteOps other) {
+ mLargestChainId = max(mLargestChainId, other.mLargestChainId);
int nUids = other.mUids.size();
for (int i = 0; i < nUids; i++) {
int uid = other.mUids.keyAt(i);
@@ -390,14 +629,27 @@ final class DiscreteRegistry {
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
+ int offsetChainId = attributionChainId;
+ if (attributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ offsetChainId = attributionChainId + mChainIdOffset;
+ if (offsetChainId > mLargestChainId) {
+ mLargestChainId = offsetChainId;
+ } else if (offsetChainId < 0) {
+ // handle overflow
+ offsetChainId = 0;
+ mLargestChainId = 0;
+ mChainIdOffset = -1 * attributionChainId;
+ }
+ }
getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
- uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
+ uidState, accessTime, accessDuration, attributionFlags, offsetChainId);
}
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_UID) != 0) {
ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>();
uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter));
@@ -406,7 +658,8 @@ final class DiscreteRegistry {
int nUids = mUids.size();
for (int i = nUids - 1; i >= 0; i--) {
mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter,
- opNamesFilter, attributionTagFilter, flagsFilter);
+ opNamesFilter, attributionTagFilter, flagsFilter, mUids.keyAt(i),
+ attributionChains);
if (mUids.valueAt(i).isEmpty()) {
mUids.removeAt(i);
}
@@ -429,10 +682,11 @@ final class DiscreteRegistry {
}
}
- private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
+ private void applyToHistoricalOps(AppOpsManager.HistoricalOps result,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
- mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i));
+ mUids.valueAt(i).applyToHistory(result, mUids.keyAt(i), attributionChains);
}
}
@@ -442,6 +696,7 @@ final class DiscreteRegistry {
out.startDocument(null, true);
out.startTag(null, TAG_HISTORY);
out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
+ out.attributeInt(null, ATTR_LARGEST_CHAIN_ID, mLargestChainId);
int nUids = mUids.size();
for (int i = 0; i < nUids; i++) {
@@ -476,8 +731,13 @@ final class DiscreteRegistry {
}
private void readFromFile(File f, long beginTimeMillis) {
+ FileInputStream stream;
+ try {
+ stream = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ return;
+ }
try {
- FileInputStream stream = new FileInputStream(f);
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
XmlUtils.beginDocument(parser, TAG_HISTORY);
@@ -487,7 +747,6 @@ final class DiscreteRegistry {
if (version != CURRENT_VERSION) {
throw new IllegalStateException("Dropping unsupported discrete history " + f);
}
-
int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_UID.equals(parser.getName())) {
@@ -498,8 +757,12 @@ final class DiscreteRegistry {
} catch (Throwable t) {
Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
+ Arrays.toString(t.getStackTrace()));
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
}
-
}
}
@@ -590,7 +853,8 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>();
packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter));
@@ -599,7 +863,8 @@ final class DiscreteRegistry {
int nPackages = mPackages.size();
for (int i = nPackages - 1; i >= 0; i--) {
mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, mPackages.keyAt(i),
+ attributionChains);
if (mPackages.valueAt(i).isEmpty()) {
mPackages.removeAt(i);
}
@@ -634,10 +899,12 @@ final class DiscreteRegistry {
return result;
}
- private void applyToHistory(AppOpsManager.HistoricalOps result, int uid) {
+ private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackages = mPackages.size();
for (int i = 0; i < nPackages; i++) {
- mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i));
+ mPackages.valueAt(i).applyToHistory(result, uid, mPackages.keyAt(i),
+ attributionChains);
}
}
@@ -705,7 +972,8 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
- @AppOpsManager.OpFlags int flagsFilter) {
+ @AppOpsManager.OpFlags int flagsFilter, int currentUid, String currentPkgName,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mPackageOps.size();
for (int i = nOps - 1; i >= 0; i--) {
int opId = mPackageOps.keyAt(i);
@@ -715,7 +983,8 @@ final class DiscreteRegistry {
continue;
}
mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter,
- attributionTagFilter, flagsFilter);
+ attributionTagFilter, flagsFilter, currentUid, currentPkgName,
+ mPackageOps.keyAt(i), attributionChains);
if (mPackageOps.valueAt(i).isEmpty()) {
mPackageOps.removeAt(i);
}
@@ -739,11 +1008,12 @@ final class DiscreteRegistry {
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName) {
+ @NonNull String packageName,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nPackageOps = mPackageOps.size();
for (int i = 0; i < nPackageOps; i++) {
mPackageOps.valueAt(i).applyToHistory(result, uid, packageName,
- mPackageOps.keyAt(i));
+ mPackageOps.keyAt(i), attributionChains);
}
}
@@ -802,7 +1072,9 @@ final class DiscreteRegistry {
private void filter(long beginTimeMillis, long endTimeMillis,
@AppOpsManager.HistoricalOpsRequestFilter int filter,
- @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
+ @Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPkgName, int currentOp,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) {
ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>();
attributedOps.put(attributionTagFilter,
@@ -814,7 +1086,9 @@ final class DiscreteRegistry {
for (int i = nTags - 1; i >= 0; i--) {
String tag = mAttributedOps.keyAt(i);
List<DiscreteOpEvent> list = mAttributedOps.valueAt(i);
- list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter);
+ list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter,
+ currentUid, currentPkgName, currentOp, mAttributedOps.keyAt(i),
+ attributionChains);
mAttributedOps.put(tag, list);
if (list.size() == 0) {
mAttributedOps.removeAt(i);
@@ -876,7 +1150,8 @@ final class DiscreteRegistry {
}
private void applyToHistory(AppOpsManager.HistoricalOps result, int uid,
- @NonNull String packageName, int op) {
+ @NonNull String packageName, int op,
+ @NonNull ArrayMap<Integer, AttributionChain> attributionChains) {
int nOps = mAttributedOps.size();
for (int i = 0; i < nOps; i++) {
String tag = mAttributedOps.keyAt(i);
@@ -884,9 +1159,21 @@ final class DiscreteRegistry {
int nEvents = events.size();
for (int j = 0; j < nEvents; j++) {
DiscreteOpEvent event = events.get(j);
+ AppOpsManager.OpEventProxyInfo proxy = null;
+ if (event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE
+ && attributionChains != null) {
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ if (chain != null && chain.isComplete()
+ && chain.isStart(packageName, uid, tag, op, event)
+ && chain.mLastVisibleEvent != null) {
+ AttributionChain.OpEvent proxyEvent = chain.mLastVisibleEvent;
+ proxy = new AppOpsManager.OpEventProxyInfo(proxyEvent.mUid,
+ proxyEvent.mPkgName, proxyEvent.mAttributionTag);
+ }
+ }
result.addDiscreteAccess(op, uid, packageName, tag, event.mUidState,
event.mOpFlag, discretizeTimeStamp(event.mNoteTime),
- discretizeDuration(event.mNoteDuration));
+ discretizeDuration(event.mNoteDuration), proxy);
}
}
}
@@ -981,6 +1268,13 @@ final class DiscreteRegistry {
mAttributionChainId = attributionChainId;
}
+ public boolean equalsExceptDuration(DiscreteOpEvent o) {
+ return mNoteTime == o.mNoteTime && mUidState == o.mUidState && mOpFlag == o.mOpFlag
+ && mAttributionFlags == o.mAttributionFlags
+ && mAttributionChainId == o.mAttributionChainId;
+
+ }
+
private void dump(@NonNull PrintWriter pw, @NonNull SimpleDateFormat sdf,
@NonNull Date date, @NonNull String prefix) {
pw.print(prefix);
@@ -1063,11 +1357,20 @@ final class DiscreteRegistry {
}
private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list,
- long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) {
+ long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter,
+ int currentUid, String currentPackageName, int currentOp, String currentAttrTag,
+ ArrayMap<Integer, AttributionChain> attributionChains) {
int n = list.size();
List<DiscreteOpEvent> result = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
DiscreteOpEvent event = list.get(i);
+ AttributionChain chain = attributionChains.get(event.mAttributionChainId);
+ // If we have an attribution chain, and this event isn't the beginning node, remove it
+ if (chain != null && !chain.isStart(currentPackageName, currentUid, currentAttrTag,
+ currentOp, event) && chain.isComplete()
+ && event.mAttributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
+ continue;
+ }
if ((event.mOpFlag & flagsFilter) != 0
&& event.mNoteTime + event.mNoteDuration > beginTimeMillis
&& event.mNoteTime < endTimeMillis) {
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index dd5df503d936..2c68aaf4f3e5 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -209,6 +209,7 @@ final class HistoricalRegistry {
mMode = other.mMode;
mBaseSnapshotInterval = other.mBaseSnapshotInterval;
mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier;
+ mDiscreteRegistry = other.mDiscreteRegistry;
}
void systemReady(@NonNull ContentResolver resolver) {
@@ -369,7 +370,7 @@ final class HistoricalRegistry {
@Nullable String attributionTag, @Nullable String[] opNames,
@OpHistoryFlags int historyFlags, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
- @NonNull RemoteCallback callback) {
+ String[] attributionExemptedPackages, @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -395,7 +396,7 @@ final class HistoricalRegistry {
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
endTimeMillis, filter, uid, packageName, opNames, attributionTag,
- flags);
+ flags, new ArraySet<>(attributionExemptedPackages));
}
final Bundle payload = new Bundle();
@@ -406,7 +407,8 @@ final class HistoricalRegistry {
void getHistoricalOps(int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @OpHistoryFlags int historyFlags,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
- @OpFlags int flags, @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @Nullable String[] attributionExemptPkgs,
+ @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
callback.sendResult(new Bundle());
return;
@@ -428,7 +430,8 @@ final class HistoricalRegistry {
if ((historyFlags & HISTORY_FLAG_DISCRETE) != 0) {
mDiscreteRegistry.addFilteredDiscreteOpsToHistoricalOps(result, beginTimeMillis,
- endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags);
+ endTimeMillis, filter, uid, packageName, opNames, attributionTag, flags,
+ new ArraySet<>(attributionExemptPkgs));
}
if ((historyFlags & HISTORY_FLAG_AGGREGATE) != 0) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index a5bb0f430609..0981f184e143 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -866,7 +866,7 @@ public class Face10 implements IHwBinder.DeathRecipient, ServiceProvider {
private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) {
final boolean hasEnrolled = !getEnrolledFaces(mSensorId, targetUserId).isEmpty();
final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext,
- mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, mCurrentUserId,
+ mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId,
hasEnrolled, mAuthenticatorIds);
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
index 70e20339ce98..5343d0d17273 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceUpdateActiveUserClient.java
@@ -34,38 +34,23 @@ public class FaceUpdateActiveUserClient extends HalClientMonitor<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 LazyDaemon<IBiometricsFace> lazyDaemon, int userId, @NonNull String owner,
+ int sensorId, 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;
+ mHasEnrolledBiometrics = hasEnrolledBiometrics;
mAuthenticatorIds = authenticatorIds;
}
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
-
- 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);
- }
- callback.onClientFinished(this, true /* success */);
- return;
- }
-
startHalOperation();
}
@@ -85,7 +70,10 @@ public class FaceUpdateActiveUserClient extends HalClientMonitor<IBiometricsFace
}
try {
- getFreshDaemon().setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
+ final IBiometricsFace daemon = getFreshDaemon();
+ daemon.setActiveUser(getTargetUserId(), storePath.getAbsolutePath());
+ mAuthenticatorIds.put(getTargetUserId(),
+ mHasEnrolledBiometrics ? daemon.getAuthenticatorId().value : 0L);
mCallback.onClientFinished(this, true /* success */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to setActiveUser: " + e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
index f1f94564c35d..0ae2e381cf14 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/AidlConversionUtils.java
@@ -80,8 +80,7 @@ final class AidlConversionUtils {
// No framework constant available
return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
} else if (aidlAcquiredInfo == AcquiredInfo.IMMOBILE) {
- // No framework constant available
- return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
+ return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMMOBILE;
} else if (aidlAcquiredInfo == AcquiredInfo.RETRYING_CAPTURE) {
// No framework constant available
return BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_UNKNOWN;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 160736433112..8d777e1c2787 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -124,10 +124,12 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
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);
+ if (getListener() != null) {
+ 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/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 184ddae9699d..88f88a8439cc 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -19,6 +19,8 @@ package com.android.server.display;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.os.Environment;
import android.os.PowerManager;
import android.text.TextUtils;
@@ -86,6 +88,9 @@ public class DisplayDeviceConfig {
// The details of the proximity sensor associated with this display.
private final SensorData mProximitySensor = new SensorData();
+ private final List<RefreshRateLimitation> mRefreshRateLimitations =
+ new ArrayList<>(2 /*initialCapacity*/);
+
// Nits and backlight values that are loaded from either the display device config file, or
// config.xml. These are the raw values and just used for the dumpsys
private float[] mRawNits;
@@ -306,6 +311,10 @@ public class DisplayDeviceConfig {
return hbmData;
}
+ public List<RefreshRateLimitation> getRefreshRateLimitations() {
+ return mRefreshRateLimitations;
+ }
+
@Override
public String toString() {
String str = "DisplayDeviceConfig{"
@@ -329,6 +338,7 @@ public class DisplayDeviceConfig {
+ ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+ ", mAmbientLightSensor=" + mAmbientLightSensor
+ ", mProximitySensor=" + mProximitySensor
+ + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
+ "}";
return str;
}
@@ -647,6 +657,13 @@ public class DisplayDeviceConfig {
mHbmData.timeWindowMillis = hbmTiming.getTimeWindowSecs_all().longValue() * 1000;
mHbmData.timeMaxMillis = hbmTiming.getTimeMaxSecs_all().longValue() * 1000;
mHbmData.timeMinMillis = hbmTiming.getTimeMinSecs_all().longValue() * 1000;
+ final RefreshRateRange rr = hbm.getRefreshRate_all();
+ if (rr != null) {
+ final float min = rr.getMinimum().floatValue();
+ final float max = rr.getMaximum().floatValue();
+ mRefreshRateLimitations.add(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
+ }
}
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index bff39a932105..182a038d10f7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -63,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
+import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.display.DisplayViewport;
import android.hardware.display.DisplayedContentSample;
@@ -130,6 +131,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
@@ -2111,6 +2113,11 @@ public final class DisplayManagerService extends SystemService {
DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
}
+ private DisplayDevice getDeviceForDisplayLocked(int displayId) {
+ final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ return display == null ? null : display.getPrimaryDisplayDeviceLocked();
+ }
+
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
@@ -3295,6 +3302,19 @@ public final class DisplayManagerService extends SystemService {
}
return null;
}
+
+ @Override
+ public List<RefreshRateLimitation> getRefreshRateLimitations(int displayId) {
+ final DisplayDeviceConfig config;
+ synchronized (mSyncRoot) {
+ final DisplayDevice device = getDeviceForDisplayLocked(displayId);
+ if (device == null) {
+ return null;
+ }
+ config = device.getDisplayDeviceConfig();
+ }
+ return config.getRefreshRateLimitations();
+ }
}
class DesiredDisplayModeSpecsObserver
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 2364a3c7c2ed..83fc9665f192 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -26,8 +28,10 @@ import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.net.Uri;
@@ -102,6 +106,7 @@ public class DisplayModeDirector {
private final DisplayObserver mDisplayObserver;
private final UdfpsObserver mUdfpsObserver;
private final SensorObserver mSensorObserver;
+ private final HbmObserver mHbmObserver;
private final DeviceConfigInterface mDeviceConfig;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
@@ -127,7 +132,7 @@ public class DisplayModeDirector {
private int mModeSwitchingType = DisplayManager.SWITCHING_TYPE_WITHIN_GROUPS;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
- this(context, handler, new RealInjector());
+ this(context, handler, new RealInjector(context));
}
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
@@ -143,11 +148,13 @@ public class DisplayModeDirector {
mDisplayObserver = new DisplayObserver(context, handler);
mBrightnessObserver = new BrightnessObserver(context, handler);
mUdfpsObserver = new UdfpsObserver();
- mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> {
+ final BallotBox ballotBox = (displayId, priority, vote) -> {
synchronized (mLock) {
updateVoteLocked(displayId, priority, vote);
}
- });
+ };
+ mSensorObserver = new SensorObserver(context, ballotBox);
+ mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
mDeviceConfig = injector.getDeviceConfig();
mAlwaysRespectAppRequest = false;
@@ -165,6 +172,7 @@ public class DisplayModeDirector {
mDisplayObserver.observe();
mBrightnessObserver.observe(sensorManager);
mSensorObserver.observe();
+ mHbmObserver.observe();
synchronized (mLock) {
// We may have a listener already registered before the call to start, so go ahead and
// notify them to pick up our newly initialized state.
@@ -596,6 +604,7 @@ public class DisplayModeDirector {
mBrightnessObserver.dumpLocked(pw);
mUdfpsObserver.dumpLocked(pw);
mSensorObserver.dumpLocked(pw);
+ mHbmObserver.dumpLocked(pw);
}
}
@@ -938,13 +947,16 @@ public class DisplayModeDirector {
// user seeing the display flickering when the switches occur.
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
+ // High-brightness-mode may need a specific range of refresh-rates to function properly.
+ public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
+
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- public static final int PRIORITY_PROXIMITY = 9;
+ public static final int PRIORITY_PROXIMITY = 10;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- public static final int PRIORITY_UDFPS = 10;
+ public static final int PRIORITY_UDFPS = 11;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1021,29 +1033,30 @@ public class DisplayModeDirector {
public static String priorityToString(int priority) {
switch (priority) {
+ case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
+ return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
+ case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE:
+ return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE";
+ case PRIORITY_APP_REQUEST_SIZE:
+ return "PRIORITY_APP_REQUEST_SIZE";
case PRIORITY_DEFAULT_REFRESH_RATE:
return "PRIORITY_DEFAULT_REFRESH_RATE";
case PRIORITY_FLICKER_REFRESH_RATE:
return "PRIORITY_FLICKER_REFRESH_RATE";
case PRIORITY_FLICKER_REFRESH_RATE_SWITCH:
return "PRIORITY_FLICKER_REFRESH_RATE_SWITCH";
- case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
- return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
- case PRIORITY_APP_REQUEST_MAX_REFRESH_RATE:
- return "PRIORITY_APP_REQUEST_MAX_REFRESH_RATE";
- case PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE:
- return "PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE";
- case PRIORITY_APP_REQUEST_SIZE:
- return "PRIORITY_APP_REQUEST_SIZE";
- case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
- return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
+ case PRIORITY_HIGH_BRIGHTNESS_MODE:
+ return "PRIORITY_HIGH_BRIGHTNESS_MODE";
+ case PRIORITY_PROXIMITY:
+ return "PRIORITY_PROXIMITY";
case PRIORITY_LOW_POWER_MODE:
return "PRIORITY_LOW_POWER_MODE";
case PRIORITY_UDFPS:
return "PRIORITY_UDFPS";
- case PRIORITY_PROXIMITY:
- return "PRIORITY_PROXIMITY";
-
+ case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
+ return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
+ case PRIORITY_USER_SETTING_PEAK_REFRESH_RATE:
+ return "PRIORITY_USER_SETTING_PEAK_REFRESH_RATE";
default:
return Integer.toString(priority);
}
@@ -2155,6 +2168,75 @@ public class DisplayModeDirector {
}
}
+ /**
+ * Listens to DisplayManager for HBM status and applies any refresh-rate restrictions for
+ * HBM that are associated with that display. Restrictions are retrieved from
+ * DisplayManagerInternal but originate in the display-device-config file.
+ */
+ private static class HbmObserver implements DisplayManager.DisplayListener {
+ private final BallotBox mBallotBox;
+ private final Handler mHandler;
+ private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray();
+ private final Injector mInjector;
+
+ private DisplayManagerInternal mDisplayManagerInternal;
+
+ HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) {
+ mInjector = injector;
+ mBallotBox = ballotBox;
+ mHandler = handler;
+ }
+
+ public void observe() {
+ mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+ mInjector.registerDisplayListener(this, mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {}
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ final BrightnessInfo info = mInjector.getBrightnessInfo(displayId);
+ if (info == null) {
+ // Display no longer there. Assume we'll get an onDisplayRemoved very soon.
+ return;
+ }
+ final boolean isHbmEnabled =
+ info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+ if (isHbmEnabled == mHbmEnabled.get(displayId)) {
+ // no change, ignore.
+ return;
+ }
+ Vote vote = null;
+ mHbmEnabled.put(displayId, isHbmEnabled);
+ if (isHbmEnabled) {
+ final List<RefreshRateLimitation> limits =
+ mDisplayManagerInternal.getRefreshRateLimitations(displayId);
+ for (int i = 0; limits != null && i < limits.size(); i++) {
+ final RefreshRateLimitation limitation = limits.get(i);
+ if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
+ vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
+ break;
+ }
+ }
+ }
+ mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
+ }
+
+ void dumpLocked(PrintWriter pw) {
+ pw.println(" HbmObserver");
+ pw.println(" mHbmEnabled: " + mHbmEnabled);
+ }
+ }
+
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
public DeviceConfigDisplaySettings() {
}
@@ -2309,10 +2391,21 @@ public class DisplayModeDirector {
void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
@NonNull ContentObserver observer);
+
+ void registerDisplayListener(@NonNull DisplayManager.DisplayListener listener,
+ Handler handler, long flags);
+
+ BrightnessInfo getBrightnessInfo(int displayId);
}
@VisibleForTesting
static class RealInjector implements Injector {
+ private final Context mContext;
+ private DisplayManager mDisplayManager;
+
+ RealInjector(Context context) {
+ mContext = context;
+ }
@Override
@NonNull
@@ -2339,6 +2432,28 @@ public class DisplayModeDirector {
cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
observer, UserHandle.USER_SYSTEM);
}
+
+ @Override
+ public void registerDisplayListener(DisplayManager.DisplayListener listener,
+ Handler handler, long flags) {
+ getDisplayManager().registerDisplayListener(listener, handler, flags);
+ }
+
+ @Override
+ public BrightnessInfo getBrightnessInfo(int displayId) {
+ final Display display = getDisplayManager().getDisplay(displayId);
+ if (display != null) {
+ return display.getBrightnessInfo();
+ }
+ return null;
+ }
+
+ private DisplayManager getDisplayManager() {
+ if (mDisplayManager == null) {
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ }
+ return mDisplayManager;
+ }
}
interface BallotBox {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index aeb1893c78b6..e6210b2a8cc9 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -45,6 +45,7 @@ import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
@@ -91,6 +92,7 @@ import android.util.IndentingPrintWriter;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -134,6 +136,8 @@ import com.android.server.location.provider.PassiveLocationProvider;
import com.android.server.location.provider.PassiveLocationProviderManager;
import com.android.server.location.provider.StationaryThrottlingLocationProvider;
import com.android.server.location.provider.proxy.ProxyLocationProvider;
+import com.android.server.location.settings.LocationSettings;
+import com.android.server.location.settings.LocationUserSettings;
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
import java.io.FileDescriptor;
@@ -270,6 +274,8 @@ public class LocationManagerService extends ILocationManager.Stub implements
mGeofenceManager = new GeofenceManager(mContext, injector);
+ mInjector.getLocationSettings().registerLocationUserSettingsListener(
+ this::onLocationUserSettingsChanged);
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
this::onLocationModeChanged);
mInjector.getSettingsHelper().addIgnoreSettingsAllowlistChangedListener(
@@ -476,6 +482,25 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
}
+ private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
+ boolean enabled = newSettings.isAdasGnssLocationEnabled();
+
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] adas gnss location enabled = " + enabled);
+ }
+
+ EVENT_LOG.logAdasLocationEnabled(userId, enabled);
+
+ Intent intent = new Intent(LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED)
+ .putExtra(LocationManager.EXTRA_ADAS_GNSS_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+ }
+
private void onLocationModeChanged(int userId) {
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
LocationManager.invalidateLocalLocationEnabledCaches();
@@ -661,7 +686,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
// clients in the system process must have an attribution tag set
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -687,7 +712,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
new IllegalArgumentException());
}
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -725,7 +750,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
}
- request = validateLocationRequest(request, identity);
+ request = validateLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
Preconditions.checkArgument(manager != null,
@@ -734,33 +759,27 @@ public class LocationManagerService extends ILocationManager.Stub implements
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
}
- private LocationRequest validateLocationRequest(LocationRequest request,
+ private LocationRequest validateLocationRequest(String provider, LocationRequest request,
CallerIdentity identity) {
+ // validate unsanitized request
if (!request.getWorkSource().isEmpty()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_DEVICE_STATS,
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- if (request.isHiddenFromAppOps()) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS,
- "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
- }
- if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS,
- "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
- }
+ // sanitize request
LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
- if (CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
- if (request.isLowPower()) {
- mContext.enforceCallingOrSelfPermission(
- permission.LOCATION_HARDWARE,
- "low power request requires " + permission.LOCATION_HARDWARE);
- }
- } else {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && GPS_PROVIDER.equals(provider)
+ && ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ sanitized.setAdasGnssBypass(true);
+ }
+
+ if (!CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
!= PERMISSION_GRANTED) {
sanitized.setLowPower(false);
@@ -786,7 +805,52 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
sanitized.setWorkSource(workSource);
- return sanitized.build();
+ request = sanitized.build();
+
+ // validate sanitized request
+ boolean isLocationProvider = mLocalService.isProvider(null, identity);
+
+ if (request.isLowPower() && CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS,
+ identity.getUid())) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.LOCATION_HARDWARE,
+ "low power request requires " + permission.LOCATION_HARDWARE);
+ }
+ if (request.isHiddenFromAppOps()) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.UPDATE_APP_OPS_STATS,
+ "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
+ }
+ if (request.isAdasGnssBypass()) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on automotive devices");
+ }
+ if (!GPS_PROVIDER.equals(provider)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on the \"gps\" provider");
+ }
+ if (!ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ throw new SecurityException(
+ "only verified adas packages may use adas gnss bypass requests");
+ }
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
+ if (request.isLocationSettingsIgnored()) {
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
+
+ return request;
}
@Override
@@ -834,7 +898,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
// clients in the system process must have an attribution tag set
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- request = validateLastLocationRequest(request);
+ request = validateLastLocationRequest(provider, request, identity);
LocationProviderManager manager = getLocationProviderManager(provider);
if (manager == null) {
@@ -844,16 +908,58 @@ public class LocationManagerService extends ILocationManager.Stub implements
return manager.getLastLocation(request, identity, permissionLevel);
}
- private LastLocationRequest validateLastLocationRequest(LastLocationRequest request) {
+ private LastLocationRequest validateLastLocationRequest(String provider,
+ LastLocationRequest request,
+ CallerIdentity identity) {
+ // sanitize request
+ LastLocationRequest.Builder sanitized = new LastLocationRequest.Builder(request);
+
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+ && GPS_PROVIDER.equals(provider)
+ && ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ sanitized.setAdasGnssBypass(true);
+ }
+
+ request = sanitized.build();
+
+ // validate request
+ boolean isLocationProvider = mLocalService.isProvider(null, identity);
+
if (request.isHiddenFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
permission.UPDATE_APP_OPS_STATS,
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
}
+
+ if (request.isAdasGnssBypass()) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on automotive devices");
+ }
+ if (!GPS_PROVIDER.equals(provider)) {
+ throw new IllegalArgumentException(
+ "adas gnss bypass requests are only allowed on the \"gps\" provider");
+ }
+ if (!ArrayUtils.contains(mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_locationDriverAssistancePackageNames),
+ identity.getPackageName())) {
+ throw new SecurityException(
+ "only verified adas packages may use adas gnss bypass requests");
+ }
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
+ }
+ }
if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS,
- "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ if (!isLocationProvider) {
+ mContext.enforceCallingOrSelfPermission(
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
+ }
}
return request;
@@ -1126,6 +1232,24 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
@Override
+ public void setAdasGnssLocationEnabledForUser(boolean enabled, int userId) {
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "setAdasGnssLocationEnabledForUser", null);
+
+ mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
+
+ mInjector.getLocationSettings().updateUserSettings(userId,
+ settings -> settings.withAdasGnssLocationEnabled(enabled));
+ }
+
+ @Override
+ public boolean isAdasGnssLocationEnabledForUser(int userId) {
+ userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, false, false, "isAdasGnssLocationEnabledForUser", null);
+ return mInjector.getLocationSettings().getUserSettings(userId).isAdasGnssLocationEnabled();
+ }
+
+ @Override
public boolean isProviderEnabledForUser(String provider, int userId) {
return mLocalService.isProviderEnabledForUser(provider, userId);
}
@@ -1555,11 +1679,12 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
}
- private static class SystemInjector implements Injector {
+ private static final class SystemInjector implements Injector {
private final Context mContext;
private final UserInfoHelper mUserInfoHelper;
+ private final LocationSettings mLocationSettings;
private final AlarmHelper mAlarmHelper;
private final SystemAppOpsHelper mAppOpsHelper;
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
@@ -1584,6 +1709,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
mContext = context;
mUserInfoHelper = userInfoHelper;
+ mLocationSettings = new LocationSettings(context);
mAlarmHelper = new SystemAlarmHelper(context);
mAppOpsHelper = new SystemAppOpsHelper(context);
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
@@ -1621,6 +1747,11 @@ public class LocationManagerService extends ILocationManager.Stub implements
}
@Override
+ public LocationSettings getLocationSettings() {
+ return mLocationSettings;
+ }
+
+ @Override
public AlarmHelper getAlarmHelper() {
return mAlarmHelper;
}
diff --git a/services/core/java/com/android/server/location/LocationShellCommand.java b/services/core/java/com/android/server/location/LocationShellCommand.java
index 937849309f96..b65338d9691d 100644
--- a/services/core/java/com/android/server/location/LocationShellCommand.java
+++ b/services/core/java/com/android/server/location/LocationShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.provider.ProviderProperties;
@@ -60,6 +61,14 @@ class LocationShellCommand extends BasicShellCommandHandler {
handleSetLocationEnabled();
return 0;
}
+ case "is-adas-gnss-location-enabled": {
+ handleIsAdasGnssLocationEnabled();
+ return 0;
+ }
+ case "set-adas-gnss-location-enabled": {
+ handleSetAdasGnssLocationEnabled();
+ return 0;
+ }
case "providers": {
String command = getNextArgRequired();
return parseProvidersCommand(command);
@@ -134,6 +143,52 @@ class LocationShellCommand extends BasicShellCommandHandler {
mService.setLocationEnabledForUser(enabled, userId);
}
+ private void handleIsAdasGnssLocationEnabled() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalStateException("command only recognized on automotive devices");
+ }
+
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ getOutPrintWriter().println(mService.isAdasGnssLocationEnabledForUser(userId));
+ }
+
+ private void handleSetAdasGnssLocationEnabled() {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ throw new IllegalStateException("command only recognized on automotive devices");
+ }
+
+ boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+
+ int userId = UserHandle.USER_CURRENT_OR_SELF;
+
+ do {
+ String option = getNextOption();
+ if (option == null) {
+ break;
+ }
+ if ("--user".equals(option)) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + option);
+ }
+ } while (true);
+
+ mService.setAdasGnssLocationEnabledForUser(enabled, userId);
+ }
+
private void handleAddTestProvider() {
String provider = getNextArgRequired();
@@ -297,6 +352,14 @@ class LocationShellCommand extends BasicShellCommandHandler {
pw.println(" set-location-enabled true|false [--user <USER_ID>]");
pw.println(" Sets the master location switch enabled state. If no user is specified,");
pw.println(" the current user is assumed.");
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+ pw.println(" is-adas-gnss-location-enabled [--user <USER_ID>]");
+ pw.println(" Gets the ADAS GNSS location enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
+ pw.println(" set-adas-gnss-location-enabled true|false [--user <USER_ID>]");
+ pw.println(" Sets the ADAS GNSS location enabled state. If no user is specified,");
+ pw.println(" the current user is assumed.");
+ }
pw.println(" providers");
pw.println(" The providers command is followed by a subcommand, as listed below:");
pw.println();
@@ -323,9 +386,8 @@ class LocationShellCommand extends BasicShellCommandHandler {
pw.println(" Common commands that may be supported by the gps provider, depending on");
pw.println(" hardware and software configurations:");
pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
- pw.println(" force_time_injection - requests NTP time injection to chipset");
- pw.println(" force_psds_injection - "
- + "requests predictive aiding data injection to chipset");
- pw.println(" request_power_stats - requests GNSS power stats update from chipset");
+ pw.println(" force_time_injection - requests NTP time injection");
+ pw.println(" force_psds_injection - requests predictive aiding data injection");
+ pw.println(" request_power_stats - requests GNSS power stats update");
}
}
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index e6d25ece93ef..db2a43f7a00d 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -55,19 +55,20 @@ public class LocationEventLog extends LocalEventLog {
private static final int EVENT_USER_SWITCHED = 1;
private static final int EVENT_LOCATION_ENABLED = 2;
- private static final int EVENT_PROVIDER_ENABLED = 3;
- private static final int EVENT_PROVIDER_MOCKED = 4;
- private static final int EVENT_PROVIDER_CLIENT_REGISTER = 5;
- private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 6;
- private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 7;
- private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 8;
- private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 9;
- private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 10;
- private static final int EVENT_PROVIDER_UPDATE_REQUEST = 11;
- private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 12;
- private static final int EVENT_PROVIDER_DELIVER_LOCATION = 13;
- private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 14;
- private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 15;
+ private static final int EVENT_ADAS_LOCATION_ENABLED = 3;
+ private static final int EVENT_PROVIDER_ENABLED = 4;
+ private static final int EVENT_PROVIDER_MOCKED = 5;
+ private static final int EVENT_PROVIDER_CLIENT_REGISTER = 6;
+ private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 7;
+ private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 8;
+ private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 9;
+ private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 10;
+ private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 11;
+ private static final int EVENT_PROVIDER_UPDATE_REQUEST = 12;
+ private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 13;
+ private static final int EVENT_PROVIDER_DELIVER_LOCATION = 14;
+ private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 15;
+ private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 16;
@GuardedBy("mAggregateStats")
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
@@ -116,6 +117,11 @@ public class LocationEventLog extends LocalEventLog {
addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
}
+ /** Logs a location enabled/disabled event. */
+ public void logAdasLocationEnabled(int userId, boolean enabled) {
+ addLogEvent(EVENT_ADAS_LOCATION_ENABLED, userId, enabled);
+ }
+
/** Logs a location provider enabled/disabled event. */
public void logProviderEnabled(String provider, int userId, boolean enabled) {
addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
@@ -219,6 +225,9 @@ public class LocationEventLog extends LocalEventLog {
return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
case EVENT_LOCATION_ENABLED:
return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
+ case EVENT_ADAS_LOCATION_ENABLED:
+ return new LocationAdasEnabledEvent(timeDelta, (Integer) args[0],
+ (Boolean) args[1]);
case EVENT_PROVIDER_ENABLED:
return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
(Boolean) args[2]);
@@ -517,6 +526,23 @@ public class LocationEventLog extends LocalEventLog {
}
}
+ private static final class LocationAdasEnabledEvent extends LogEvent {
+
+ private final int mUserId;
+ private final boolean mEnabled;
+
+ LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled) {
+ super(timeDelta);
+ mUserId = userId;
+ mEnabled = enabled;
+ }
+
+ @Override
+ public String getLogString() {
+ return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
+ }
+ }
+
/**
* Aggregate statistics for a single package under a single provider.
*/
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 1cccf08b0367..f3dcfbbf2c0a 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -771,10 +771,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
boolean enabled = mContext.getSystemService(LocationManager.class)
.isLocationEnabledForUser(UserHandle.CURRENT);
- // .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
+ // .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS)
enabled |= (mProviderRequest != null
&& mProviderRequest.isActive()
- && mProviderRequest.isLocationSettingsIgnored());
+ && mProviderRequest.isBypass());
// ... and, finally, disable anyway, if device is being shut down
enabled &= !mShutdown;
diff --git a/services/core/java/com/android/server/location/injector/Injector.java b/services/core/java/com/android/server/location/injector/Injector.java
index b0351184ffe5..173fd13c11a1 100644
--- a/services/core/java/com/android/server/location/injector/Injector.java
+++ b/services/core/java/com/android/server/location/injector/Injector.java
@@ -17,6 +17,7 @@
package com.android.server.location.injector;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.location.settings.LocationSettings;
/**
* Injects various location dependencies so that they may be controlled by tests.
@@ -27,6 +28,9 @@ public interface Injector {
/** Returns a UserInfoHelper. */
UserInfoHelper getUserInfoHelper();
+ /** Returns a LocationSettings. */
+ LocationSettings getLocationSettings();
+
/** Returns an AlarmHelper. */
AlarmHelper getAlarmHelper();
diff --git a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
index c315da476d99..3e8da7d7478a 100644
--- a/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemSettingsHelper.java
@@ -670,8 +670,6 @@ public class SystemSettingsHelper extends SettingsHelper {
}
}
-
-
private static class PackageTagsListSetting extends DeviceConfigSetting {
private final Supplier<ArrayMap<String, ArraySet<String>>> mBaseValuesSupplier;
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 8d335b83d99c..43886f7cb87b 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -113,6 +113,8 @@ import com.android.server.location.injector.UserInfoHelper;
import com.android.server.location.injector.UserInfoHelper.UserListener;
import com.android.server.location.listeners.ListenerMultiplexer;
import com.android.server.location.listeners.RemoteListenerRegistration;
+import com.android.server.location.settings.LocationSettings;
+import com.android.server.location.settings.LocationUserSettings;
import java.io.FileDescriptor;
import java.lang.annotation.Retention;
@@ -549,6 +551,19 @@ public class LocationProviderManager extends
}
@GuardedBy("mLock")
+ final boolean onAdasGnssLocationEnabledChanged(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (getIdentity().getUserId() == userId) {
+ return onProviderLocationRequestChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
final boolean onForegroundChanged(int uid, boolean foreground) {
if (Build.IS_DEBUGGABLE) {
Preconditions.checkState(Thread.holdsLock(mLock));
@@ -592,8 +607,8 @@ public class LocationProviderManager extends
onHighPowerUsageChanged();
updateService();
- // if location settings ignored has changed then the active state may have changed
- return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored();
+ // if bypass state has changed then the active state may have changed
+ return oldRequest.isBypass() != newRequest.isBypass();
}
private LocationRequest calculateProviderLocationRequest() {
@@ -616,9 +631,24 @@ public class LocationProviderManager extends
if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
getIdentity().getPackageName(), getIdentity().getAttributionTag())
&& !mLocationManagerInternal.isProvider(null, getIdentity())) {
- builder.setLocationSettingsIgnored(false);
locationSettingsIgnored = false;
}
+
+ builder.setLocationSettingsIgnored(locationSettingsIgnored);
+ }
+
+ boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
+ if (adasGnssBypass) {
+ // if we are not currently allowed use adas gnss bypass, disable it
+ if (!GPS_PROVIDER.equals(mName)) {
+ Log.e(TAG, "adas gnss bypass request received in non-gps provider");
+ adasGnssBypass = false;
+ } else if (!mLocationSettings.getUserSettings(
+ getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
+ adasGnssBypass = false;
+ }
+
+ builder.setAdasGnssBypass(adasGnssBypass);
}
if (!locationSettingsIgnored && !isThrottlingExempt()) {
@@ -769,7 +799,7 @@ public class LocationProviderManager extends
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
getPermissionLevel(),
- getRequest().isLocationSettingsIgnored(),
+ getRequest().isBypass(),
maxLocationAgeMs);
if (lastLocation != null) {
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
@@ -1114,7 +1144,7 @@ public class LocationProviderManager extends
Location lastLocation = getLastLocationUnsafe(
getIdentity().getUserId(),
getPermissionLevel(),
- getRequest().isLocationSettingsIgnored(),
+ getRequest().isBypass(),
MAX_CURRENT_LOCATION_AGE_MS);
if (lastLocation != null) {
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
@@ -1267,6 +1297,7 @@ public class LocationProviderManager extends
private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
protected final LocationManagerInternal mLocationManagerInternal;
+ protected final LocationSettings mLocationSettings;
protected final SettingsHelper mSettingsHelper;
protected final UserInfoHelper mUserHelper;
protected final AlarmHelper mAlarmHelper;
@@ -1280,6 +1311,8 @@ public class LocationProviderManager extends
protected final LocationFudger mLocationFudger;
private final UserListener mUserChangedListener = this::onUserChanged;
+ private final LocationSettings.LocationUserSettingsListener mLocationUserSettingsListener =
+ this::onLocationUserSettingsChanged;
private final UserSettingChangedListener mLocationEnabledChangedListener =
this::onLocationEnabledChanged;
private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
@@ -1332,6 +1365,7 @@ public class LocationProviderManager extends
mLocationManagerInternal = Objects.requireNonNull(
LocalServices.getService(LocationManagerInternal.class));
+ mLocationSettings = injector.getLocationSettings();
mSettingsHelper = injector.getSettingsHelper();
mUserHelper = injector.getUserInfoHelper();
mAlarmHelper = injector.getAlarmHelper();
@@ -1362,6 +1396,7 @@ public class LocationProviderManager extends
mStateChangedListener = listener;
mUserHelper.addListener(mUserChangedListener);
+ mLocationSettings.registerLocationUserSettingsListener(mLocationUserSettingsListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
final long identity = Binder.clearCallingIdentity();
@@ -1389,6 +1424,7 @@ public class LocationProviderManager extends
}
mUserHelper.removeListener(mUserChangedListener);
+ mLocationSettings.unregisterLocationUserSettingsListener(mLocationUserSettingsListener);
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
// if external entities are registering listeners it's their responsibility to
@@ -1550,7 +1586,7 @@ public class LocationProviderManager extends
public @Nullable Location getLastLocation(LastLocationRequest request,
CallerIdentity identity, @PermissionLevel int permissionLevel) {
- if (!isActive(request.isLocationSettingsIgnored(), identity)) {
+ if (!isActive(request.isBypass(), identity)) {
return null;
}
@@ -1564,7 +1600,7 @@ public class LocationProviderManager extends
getLastLocationUnsafe(
identity.getUserId(),
permissionLevel,
- request.isLocationSettingsIgnored(),
+ request.isBypass(),
Long.MAX_VALUE),
permissionLevel);
@@ -1584,7 +1620,7 @@ public class LocationProviderManager extends
* location if necessary.
*/
public @Nullable Location getLastLocationUnsafe(int userId,
- @PermissionLevel int permissionLevel, boolean ignoreLocationSettings,
+ @PermissionLevel int permissionLevel, boolean isBypass,
long maximumAgeMs) {
if (userId == UserHandle.USER_ALL) {
// find the most recent location across all users
@@ -1592,7 +1628,7 @@ public class LocationProviderManager extends
final int[] runningUserIds = mUserHelper.getRunningUserIds();
for (int i = 0; i < runningUserIds.length; i++) {
Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
- ignoreLocationSettings, maximumAgeMs);
+ isBypass, maximumAgeMs);
if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
> lastLocation.getElapsedRealtimeNanos())) {
lastLocation = next;
@@ -1601,7 +1637,7 @@ public class LocationProviderManager extends
return lastLocation;
} else if (userId == UserHandle.USER_CURRENT) {
return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
- ignoreLocationSettings, maximumAgeMs);
+ isBypass, maximumAgeMs);
}
Preconditions.checkArgument(userId >= 0);
@@ -1613,7 +1649,7 @@ public class LocationProviderManager extends
if (lastLocation == null) {
location = null;
} else {
- location = lastLocation.get(permissionLevel, ignoreLocationSettings);
+ location = lastLocation.get(permissionLevel, isBypass);
}
}
@@ -1925,7 +1961,7 @@ public class LocationProviderManager extends
// provider, under the assumption that once we send the request off, the provider will
// immediately attempt to deliver a new location satisfying that request.
long delayMs;
- if (!oldRequest.isLocationSettingsIgnored() && newRequest.isLocationSettingsIgnored()) {
+ if (!oldRequest.isBypass() && newRequest.isBypass()) {
delayMs = 0;
} else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
// if the interval has increased, tell the provider immediately, so it can save power
@@ -2002,12 +2038,12 @@ public class LocationProviderManager extends
return false;
}
- boolean locationSettingsIgnored = registration.getRequest().isLocationSettingsIgnored();
- if (!isActive(locationSettingsIgnored, registration.getIdentity())) {
+ boolean isBypass = registration.getRequest().isBypass();
+ if (!isActive(isBypass, registration.getIdentity())) {
return false;
}
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
case LOCATION_MODE_FOREGROUND_ONLY:
if (!registration.isForeground()) {
@@ -2036,15 +2072,15 @@ public class LocationProviderManager extends
return true;
}
- private boolean isActive(boolean locationSettingsIgnored, CallerIdentity identity) {
+ private boolean isActive(boolean isBypass, CallerIdentity identity) {
if (identity.isSystemServer()) {
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
if (!isEnabled(mUserHelper.getCurrentUserId())) {
return false;
}
}
} else {
- if (!locationSettingsIgnored) {
+ if (!isBypass) {
if (!isEnabled(identity.getUserId())) {
return false;
}
@@ -2071,6 +2107,7 @@ public class LocationProviderManager extends
long intervalMs = ProviderRequest.INTERVAL_DISABLED;
int quality = LocationRequest.QUALITY_LOW_POWER;
long maxUpdateDelayMs = Long.MAX_VALUE;
+ boolean adasGnssBypass = false;
boolean locationSettingsIgnored = false;
boolean lowPower = true;
@@ -2086,6 +2123,7 @@ public class LocationProviderManager extends
intervalMs = min(request.getIntervalMillis(), intervalMs);
quality = min(request.getQuality(), quality);
maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
+ adasGnssBypass |= request.isAdasGnssBypass();
locationSettingsIgnored |= request.isLocationSettingsIgnored();
lowPower &= request.isLowPower();
}
@@ -2123,6 +2161,7 @@ public class LocationProviderManager extends
.setIntervalMillis(intervalMs)
.setQuality(quality)
.setMaxUpdateDelayMillis(maxUpdateDelayMs)
+ .setAdasGnssBypass(adasGnssBypass)
.setLocationSettingsIgnored(locationSettingsIgnored)
.setLowPower(lowPower)
.setWorkSource(workSource)
@@ -2191,6 +2230,16 @@ public class LocationProviderManager extends
}
}
+ private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
+ synchronized (mLock) {
+ updateRegistrations(
+ registration -> registration.onAdasGnssLocationEnabledChanged(userId));
+ }
+ }
+ }
+
private void onLocationEnabledChanged(int userId) {
synchronized (mLock) {
if (mState == STATE_STOPPED) {
@@ -2560,16 +2609,16 @@ public class LocationProviderManager extends
}
public @Nullable Location get(@PermissionLevel int permissionLevel,
- boolean ignoreLocationSettings) {
+ boolean isBypass) {
switch (permissionLevel) {
case PERMISSION_FINE:
- if (ignoreLocationSettings) {
+ if (isBypass) {
return mFineBypassLocation;
} else {
return mFineLocation;
}
case PERMISSION_COARSE:
- if (ignoreLocationSettings) {
+ if (isBypass) {
return mCoarseBypassLocation;
} else {
return mCoarseLocation;
diff --git a/services/core/java/com/android/server/location/settings/LocationSettings.java b/services/core/java/com/android/server/location/settings/LocationSettings.java
new file mode 100644
index 000000000000..d52153893970
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/LocationSettings.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+import android.content.Context;
+import android.os.Environment;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.FgThread;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Function;
+
+/**
+ * Accessor for location user settings. Ensure there is only ever one instance as multiple instances
+ * don't play nicely with each other.
+ */
+public class LocationSettings {
+
+ /** Listens for changes to location user settings. */
+ public interface LocationUserSettingsListener {
+ /** Invoked when location user settings have changed for the given user. */
+ void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings);
+ }
+
+ private static final String LOCATION_DIRNAME = "location";
+ private static final String LOCATION_SETTINGS_FILENAME = "settings";
+
+ final Context mContext;
+
+ @GuardedBy("mUserSettings")
+ private final SparseArray<LocationUserSettingsStore> mUserSettings;
+ private final CopyOnWriteArrayList<LocationUserSettingsListener> mUserSettingsListeners;
+
+ public LocationSettings(Context context) {
+ mContext = context;
+ mUserSettings = new SparseArray<>(1);
+ mUserSettingsListeners = new CopyOnWriteArrayList<>();
+ }
+
+ /** Registers a listener for changes to location user settings. */
+ public final void registerLocationUserSettingsListener(LocationUserSettingsListener listener) {
+ mUserSettingsListeners.add(listener);
+ }
+
+ /** Unregisters a listener for changes to location user settings. */
+ public final void unregisterLocationUserSettingsListener(
+ LocationUserSettingsListener listener) {
+ mUserSettingsListeners.remove(listener);
+ }
+
+ protected File getUserSettingsDir(int userId) {
+ return Environment.getDataSystemDeDirectory(userId);
+ }
+
+ protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
+ return new LocationUserSettingsStore(userId, file);
+ }
+
+ private LocationUserSettingsStore getUserSettingsStore(int userId) {
+ synchronized (mUserSettings) {
+ LocationUserSettingsStore settingsStore = mUserSettings.get(userId);
+ if (settingsStore == null) {
+ File file = new File(new File(getUserSettingsDir(userId), LOCATION_DIRNAME),
+ LOCATION_SETTINGS_FILENAME);
+ settingsStore = createUserSettingsStore(userId, file);
+ mUserSettings.put(userId, settingsStore);
+ }
+ return settingsStore;
+ }
+ }
+
+ /** Retrieves the current state of location user settings. */
+ public final LocationUserSettings getUserSettings(int userId) {
+ return getUserSettingsStore(userId).get();
+ }
+
+ /** Updates the current state of location user settings for the given user. */
+ public final void updateUserSettings(int userId,
+ Function<LocationUserSettings, LocationUserSettings> updater) {
+ getUserSettingsStore(userId).update(updater);
+ }
+
+ @VisibleForTesting
+ final void flushFiles() throws InterruptedException {
+ synchronized (mUserSettings) {
+ int size = mUserSettings.size();
+ for (int i = 0; i < size; i++) {
+ mUserSettings.valueAt(i).flushFile();
+ }
+ }
+ }
+
+ @VisibleForTesting
+ final void deleteFiles() throws InterruptedException {
+ synchronized (mUserSettings) {
+ int size = mUserSettings.size();
+ for (int i = 0; i < size; i++) {
+ mUserSettings.valueAt(i).deleteFile();
+ }
+ }
+ }
+
+ protected final void fireListeners(int userId, LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ for (LocationUserSettingsListener listener : mUserSettingsListeners) {
+ listener.onLocationUserSettingsChanged(userId, oldSettings, newSettings);
+ }
+ }
+
+ class LocationUserSettingsStore extends SettingsStore<LocationUserSettings> {
+
+ protected final int mUserId;
+
+ LocationUserSettingsStore(int userId, File file) {
+ super(file);
+ mUserId = userId;
+ }
+
+ @Override
+ protected LocationUserSettings read(int version, DataInput in) throws IOException {
+ return filterSettings(LocationUserSettings.read(mContext.getResources(), version, in));
+ }
+
+ @Override
+ protected void write(DataOutput out, LocationUserSettings settings) throws IOException {
+ settings.write(out);
+ }
+
+ @Override
+ public void update(Function<LocationUserSettings, LocationUserSettings> updater) {
+ super.update(settings -> filterSettings(updater.apply(settings)));
+ }
+
+ @Override
+ protected void onChange(LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ FgThread.getExecutor().execute(() -> fireListeners(mUserId, oldSettings, newSettings));
+ }
+
+ private LocationUserSettings filterSettings(LocationUserSettings settings) {
+ if (settings.isAdasGnssLocationEnabled()
+ && !mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
+ // prevent non-automotive devices from ever enabling this
+ settings = settings.withAdasGnssLocationEnabled(false);
+ }
+ return settings;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/settings/LocationUserSettings.java b/services/core/java/com/android/server/location/settings/LocationUserSettings.java
new file mode 100644
index 000000000000..283255ef4b22
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/LocationUserSettings.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import android.content.res.Resources;
+
+import com.android.internal.R;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Objects;
+
+/** Holds the state of location user settings. */
+public final class LocationUserSettings implements SettingsStore.VersionedSettings {
+
+ // remember to bump this version code and add the appropriate upgrade logic whenever the format
+ // is changed.
+ private static final int VERSION = 1;
+
+ private final boolean mAdasGnssLocationEnabled;
+
+ private LocationUserSettings(boolean adasGnssLocationEnabled) {
+ mAdasGnssLocationEnabled = adasGnssLocationEnabled;
+ }
+
+ @Override
+ public int getVersion() {
+ return VERSION;
+ }
+
+ public boolean isAdasGnssLocationEnabled() {
+ return mAdasGnssLocationEnabled;
+ }
+
+ /** Returns an instance with ADAS GNSS location enabled state set as given. */
+ public LocationUserSettings withAdasGnssLocationEnabled(boolean adasEnabled) {
+ if (adasEnabled == mAdasGnssLocationEnabled) {
+ return this;
+ }
+
+ return new LocationUserSettings(adasEnabled);
+ }
+
+ void write(DataOutput out) throws IOException {
+ out.writeBoolean(mAdasGnssLocationEnabled);
+ }
+
+ static LocationUserSettings read(Resources resources, int version, DataInput in)
+ throws IOException {
+ boolean adasGnssLocationEnabled;
+
+ // upgrade code goes here. remember to bump the version field when changing the format
+ switch (version) {
+ default:
+ // set all fields to defaults
+ adasGnssLocationEnabled = resources.getBoolean(
+ R.bool.config_defaultAdasGnssLocationEnabled);
+ break;
+ case 1:
+ adasGnssLocationEnabled = in.readBoolean();
+ // fall through
+ }
+
+ return new LocationUserSettings(adasGnssLocationEnabled);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof LocationUserSettings)) {
+ return false;
+ }
+ LocationUserSettings that = (LocationUserSettings) o;
+ return mAdasGnssLocationEnabled == that.mAdasGnssLocationEnabled;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAdasGnssLocationEnabled);
+ }
+}
diff --git a/services/core/java/com/android/server/location/settings/SettingsStore.java b/services/core/java/com/android/server/location/settings/SettingsStore.java
new file mode 100644
index 000000000000..01338a3129da
--- /dev/null
+++ b/services/core/java/com/android/server/location/settings/SettingsStore.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.settings.SettingsStore.VersionedSettings.VERSION_DOES_NOT_EXIST;
+
+import android.util.AtomicFile;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.concurrent.CountDownLatch;
+import java.util.function.Function;
+
+/** Base class for read/write/versioning functionality for storing persistent settings to a file. */
+abstract class SettingsStore<T extends SettingsStore.VersionedSettings> {
+
+ interface VersionedSettings {
+ /** Represents that the settings do not exist. */
+ int VERSION_DOES_NOT_EXIST = Integer.MAX_VALUE;
+
+ /** Must always return a version number less than {@link #VERSION_DOES_NOT_EXIST}. */
+ int getVersion();
+ }
+
+ private final AtomicFile mFile;
+
+ @GuardedBy("this")
+ private boolean mInitialized;
+ @GuardedBy("this")
+ private T mCache;
+
+ protected SettingsStore(File file) {
+ mFile = new AtomicFile(file);
+ }
+
+ /**
+ * Must be implemented to read in a settings instance, and upgrade to the appropriate version
+ * where necessary. If the provided version is {@link VersionedSettings#VERSION_DOES_NOT_EXIST}
+ * then the DataInput will be empty, and the method should return a settings instance with all
+ * settings set to the default value.
+ */
+ protected abstract T read(int version, DataInput in) throws IOException;
+
+ /**
+ * Must be implemented to write the given settings to the given DataOutput.
+ */
+ protected abstract void write(DataOutput out, T settings) throws IOException;
+
+ /**
+ * Invoked when settings change, and while holding the internal lock. If used to invoke
+ * listeners, ensure they are not invoked while holding the lock (ie, asynchronously).
+ */
+ protected abstract void onChange(T oldSettings, T newSettings);
+
+ public final synchronized void initializeCache() {
+ if (!mInitialized) {
+ if (mFile.exists()) {
+ try (DataInputStream is = new DataInputStream(mFile.openRead())) {
+ mCache = read(is.readInt(), is);
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+ } catch (IOException e) {
+ Log.e(TAG, "error reading location settings (" + mFile
+ + "), falling back to defaults", e);
+ }
+ }
+
+ if (mCache == null) {
+ try {
+ mCache = read(VERSION_DOES_NOT_EXIST,
+ new DataInputStream(new ByteArrayInputStream(new byte[0])));
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ mInitialized = true;
+ }
+ }
+
+ public final synchronized T get() {
+ initializeCache();
+ return mCache;
+ }
+
+ public synchronized void update(Function<T, T> updater) {
+ initializeCache();
+
+ T oldSettings = mCache;
+ T newSettings = Objects.requireNonNull(updater.apply(oldSettings));
+ if (oldSettings.equals(newSettings)) {
+ return;
+ }
+
+ mCache = newSettings;
+ Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
+
+ writeLazily(newSettings);
+
+ onChange(oldSettings, newSettings);
+ }
+
+ @VisibleForTesting
+ synchronized void flushFile() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ BackgroundThread.getExecutor().execute(latch::countDown);
+ latch.await();
+ }
+
+ @VisibleForTesting
+ synchronized void deleteFile() throws InterruptedException {
+ CountDownLatch latch = new CountDownLatch(1);
+ BackgroundThread.getExecutor().execute(() -> {
+ mFile.delete();
+ latch.countDown();
+ });
+ latch.await();
+ }
+
+ private void writeLazily(T settings) {
+ BackgroundThread.getExecutor().execute(() -> {
+ FileOutputStream os = null;
+ try {
+ os = mFile.startWrite();
+ DataOutputStream out = new DataOutputStream(os);
+ out.writeInt(settings.getVersion());
+ write(out, settings);
+ mFile.finishWrite(os);
+ } catch (IOException e) {
+ mFile.failWrite(os);
+ Log.e(TAG, "failure serializing location settings", e);
+ } catch (Throwable e) {
+ mFile.failWrite(os);
+ throw e;
+ }
+ });
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 21f68aecd25b..d791bd69236c 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1235,11 +1235,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- synchronized (mUidRulesFirstLock) {
- synchronized (mNetworkPoliciesSecondLock) {
- upgradeWifiMeteredOverrideAL();
- }
- }
+ upgradeWifiMeteredOverride();
// Only need to perform upgrade logic once
mContext.unregisterReceiver(this);
}
@@ -2617,34 +2613,43 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* Perform upgrade step of moving any user-defined meterness overrides over
* into {@link WifiConfiguration}.
*/
- @GuardedBy({"mNetworkPoliciesSecondLock", "mUidRulesFirstLock"})
- private void upgradeWifiMeteredOverrideAL() {
- boolean modified = false;
+ private void upgradeWifiMeteredOverride() {
+ final ArrayMap<String, Boolean> wifiNetworkIds = new ArrayMap<>();
+ synchronized (mNetworkPoliciesSecondLock) {
+ for (int i = 0; i < mNetworkPolicy.size();) {
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
+ if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
+ && !policy.inferred) {
+ mNetworkPolicy.removeAt(i);
+ wifiNetworkIds.put(policy.template.getNetworkId(), policy.metered);
+ } else {
+ i++;
+ }
+ }
+ }
+
+ if (wifiNetworkIds.isEmpty()) {
+ return;
+ }
final WifiManager wm = mContext.getSystemService(WifiManager.class);
final List<WifiConfiguration> configs = wm.getConfiguredNetworks();
- for (int i = 0; i < mNetworkPolicy.size(); ) {
- final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
- if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI
- && !policy.inferred) {
- mNetworkPolicy.removeAt(i);
- modified = true;
-
- final String networkId = resolveNetworkId(policy.template.getNetworkId());
- for (WifiConfiguration config : configs) {
- if (Objects.equals(resolveNetworkId(config), networkId)) {
- Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
- config.meteredOverride = policy.metered
- ? WifiConfiguration.METERED_OVERRIDE_METERED
- : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
- wm.updateNetwork(config);
- }
- }
- } else {
- i++;
+ for (int i = 0; i < configs.size(); ++i) {
+ final WifiConfiguration config = configs.get(i);
+ final String networkId = resolveNetworkId(config);
+ final Boolean metered = wifiNetworkIds.get(networkId);
+ if (metered != null) {
+ Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint");
+ config.meteredOverride = metered
+ ? WifiConfiguration.METERED_OVERRIDE_METERED
+ : WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
+ wm.updateNetwork(config);
}
}
- if (modified) {
- writePolicyAL();
+
+ synchronized (mUidRulesFirstLock) {
+ synchronized (mNetworkPoliciesSecondLock) {
+ writePolicyAL();
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a3f3a3a503c8..d78fbdb53d8d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -140,6 +140,7 @@ import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.ITransientNotificationCallback;
import android.app.IUriGrantsManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -549,6 +550,8 @@ public class NotificationManagerService extends SystemService {
// Used for rate limiting toasts by package.
private MultiRateLimiter mToastRateLimiter;
+ private KeyguardManager mKeyguardManager;
+
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -2008,6 +2011,11 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
+ void setKeyguardManager(KeyguardManager keyguardManager) {
+ mKeyguardManager = keyguardManager;
+ }
+
+ @VisibleForTesting
ShortcutHelper getShortcutHelper() {
return mShortcutHelper;
}
@@ -2653,6 +2661,7 @@ public class NotificationManagerService extends SystemService {
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
mZenModeHelper.onSystemReady();
RoleObserver roleObserver = new RoleObserver(getContext(),
getContext().getSystemService(RoleManager.class),
@@ -3806,15 +3815,18 @@ public class NotificationManagerService extends SystemService {
enforceDeletingChannelHasNoFgService(pkg, callingUser, channelId);
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
callingUser, REASON_CHANNEL_REMOVED, null);
- mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
- // Remove from both recent notification archive and notification history
- mArchive.removeChannelNotifications(pkg, callingUser, channelId);
- mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
- mListeners.notifyNotificationChannelChanged(pkg,
- UserHandle.getUserHandleForUid(callingUid),
- mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
- NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
- handleSavePolicyFile();
+ boolean previouslyExisted = mPreferencesHelper.deleteNotificationChannel(
+ pkg, callingUid, channelId);
+ if (previouslyExisted) {
+ // Remove from both recent notification archive and notification history
+ mArchive.removeChannelNotifications(pkg, callingUser, channelId);
+ mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
+ mListeners.notifyNotificationChannelChanged(pkg,
+ UserHandle.getUserHandleForUid(callingUid),
+ mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
+ NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
+ handleSavePolicyFile();
+ }
}
@Override
@@ -7388,7 +7400,6 @@ public class NotificationManagerService extends SystemService {
boolean beep = false;
boolean blink = false;
- final Notification notification = record.getSbn().getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
@@ -7410,7 +7421,7 @@ public class NotificationManagerService extends SystemService {
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
@@ -7433,7 +7444,7 @@ public class NotificationManagerService extends SystemService {
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) {
- sendAccessibilityEvent(notification, record.getSbn().getPackageName());
+ sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
if (DBG) Slog.v(TAG, "Interrupting!");
@@ -8261,17 +8272,30 @@ public class NotificationManagerService extends SystemService {
return (x < low) ? low : ((x > high) ? high : x);
}
- void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
+ void sendAccessibilityEvent(NotificationRecord record) {
if (!mAccessibilityManager.isEnabled()) {
return;
}
- AccessibilityEvent event =
+ final Notification notification = record.getNotification();
+ final CharSequence packageName = record.getSbn().getPackageName();
+ final AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
event.setPackageName(packageName);
event.setClassName(Notification.class.getName());
- event.setParcelableData(notification);
- CharSequence tickerText = notification.tickerText;
+ final int visibilityOverride = record.getPackageVisibilityOverride();
+ final int notifVisibility = visibilityOverride == NotificationManager.VISIBILITY_NO_OVERRIDE
+ ? notification.visibility : visibilityOverride;
+ final int userId = record.getUser().getIdentifier();
+ final boolean needPublic = userId >= 0 && mKeyguardManager.isDeviceLocked(userId);
+ if (needPublic && notifVisibility != Notification.VISIBILITY_PUBLIC) {
+ // Emit the public version if we're on the lockscreen and this notification isn't
+ // publicly visible.
+ event.setParcelableData(notification.publicVersion);
+ } else {
+ event.setParcelableData(notification);
+ }
+ final CharSequence tickerText = notification.tickerText;
if (!TextUtils.isEmpty(tickerText)) {
event.getText().add(tickerText);
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 03676b5556d9..96bde3df1e68 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -1126,20 +1126,21 @@ public class PreferencesHelper implements RankingConfig {
}
@Override
- public void deleteNotificationChannel(String pkg, int uid, String channelId) {
+ public boolean deleteNotificationChannel(String pkg, int uid, String channelId) {
synchronized (mPackagePreferences) {
PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
if (r == null) {
- return;
+ return false;
}
NotificationChannel channel = r.channels.get(channelId);
if (channel != null) {
- deleteNotificationChannelLocked(channel, pkg, uid);
+ return deleteNotificationChannelLocked(channel, pkg, uid);
}
+ return false;
}
}
- private void deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
+ private boolean deleteNotificationChannelLocked(NotificationChannel channel, String pkg, int uid) {
if (!channel.isDeleted()) {
channel.setDeleted(true);
channel.setDeletedTimeMs(System.currentTimeMillis());
@@ -1151,7 +1152,9 @@ public class PreferencesHelper implements RankingConfig {
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
updateChannelsBypassingDnd();
}
+ return true;
}
+ return false;
}
@Override
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b1d654671c2d..398259333e16 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -53,7 +53,7 @@ public interface RankingConfig {
NotificationChannel getConversationNotificationChannel(String pkg, int uid, String channelId,
String conversationId, boolean returnParentIfNoConversationChannel,
boolean includeDeleted);
- void deleteNotificationChannel(String pkg, int uid, String channelId);
+ boolean deleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
void permanentlyDeleteNotificationChannels(String pkg, int uid);
ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a98f113a9d57..b144ff27c993 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -417,7 +417,14 @@ public class ZenModeHelper {
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
+ String pkg = rule.pkg != null
+ ? rule.pkg
+ : (rule.component != null)
+ ? rule.component.getPackageName()
+ : (rule.configurationActivity != null)
+ ? rule.configurationActivity.getPackageName()
+ : null;
+ if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5fd8e3c6e302..44f7d8869322 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -177,8 +177,10 @@ public class PackageDexOptimizer {
private int performDexOptLI(AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
+ // ClassLoader only refers non-native (jar) shared libraries and must ignore
+ // native (so) shared libraries. See also LoadedApk#createSharedLibraryLoader().
final List<SharedLibraryInfo> sharedLibraries = pkgSetting.getPkgState()
- .getUsesLibraryInfos();
+ .getNonNativeUsesLibraryInfos();
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(
AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting),
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 60a757118222..d2ed08f66944 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -157,6 +157,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private volatile boolean mOkToSendBroadcasts = false;
private volatile boolean mBypassNextStagedInstallerCheck = false;
+ private volatile boolean mBypassNextAllowedApexUpdateCheck = false;
/**
* File storing persisted {@link #mSessions} metadata.
@@ -650,6 +651,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
throw new IllegalArgumentException(
"Non-staged APEX session doesn't support INSTALL_ENABLE_ROLLBACK");
}
+ if (isCalledBySystemOrShell(callingUid) || mBypassNextAllowedApexUpdateCheck) {
+ params.installFlags |= PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
+ } else {
+ // Only specific APEX updates (installed through ADB, or for CTS tests) can disable
+ // allowed APEX update check.
+ params.installFlags &= ~PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK;
+ }
}
if ((params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
@@ -674,6 +682,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
mBypassNextStagedInstallerCheck = false;
+ mBypassNextAllowedApexUpdateCheck = false;
+
if (!params.isMultiPackage) {
// Only system components can circumvent runtime permissions when installing.
if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
@@ -1106,6 +1116,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mBypassNextStagedInstallerCheck = value;
}
+ @Override
+ public void bypassNextAllowedApexUpdateCheck(boolean value) {
+ if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
+ throw new SecurityException("Caller not allowed to bypass allowed apex update check");
+ }
+ mBypassNextAllowedApexUpdateCheck = value;
+ }
+
/**
* Set an installer to allow for the unlimited silent updates.
*/
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 4b0eb6546888..acc83cfd05b6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -147,6 +147,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
+import com.android.server.SystemConfig;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2238,6 +2239,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
.setAdmin(mInstallSource.installerPackageName)
.write();
}
+
+ // Check if APEX update is allowed. We do this check in handleInstall, since this is one of
+ // the places that:
+ // * Shared between staged and non-staged APEX update flows.
+ // * Only is called after boot completes.
+ // The later is important, since isApexUpdateAllowed check depends on the
+ // ModuleInfoProvider, which is only populated after device has booted.
+ if (isApexSession()) {
+ boolean checkApexUpdateAllowed =
+ (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK)
+ == 0;
+ synchronized (mLock) {
+ if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName)) {
+ onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
+ "Update of APEX package " + mPackageName + " is not allowed");
+ return;
+ }
+ }
+ }
+
if (params.isStaged) {
mStagingManager.commitSession(mStagedSession);
// TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
@@ -2776,6 +2797,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return sessionContains((s) -> !s.isApexSession());
}
+ private boolean isApexUpdateAllowed(String apexPackageName) {
+ return mPm.getModuleInfo(apexPackageName, 0) != null
+ || SystemConfig.getInstance().getAllowedVendorApexes().contains(apexPackageName);
+ }
+
/**
* Validate apex install.
* <p>
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a70a1132360a..2419873cdc41 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12798,21 +12798,6 @@ public class PackageManagerService extends IPackageManager.Stub
return performDexOpt(new DexoptOptions(packageName, compilerFilter, flags));
}
- /**
- * Ask the package manager to compile layouts in the given package.
- */
- @Override
- public boolean compileLayouts(String packageName) {
- AndroidPackage pkg;
- synchronized (mLock) {
- pkg = mPackages.get(packageName);
- if (pkg == null) {
- return false;
- }
- }
- return mViewCompiler.compileLayouts(pkg);
- }
-
/*package*/ boolean performDexOpt(DexoptOptions options) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
@@ -21495,6 +21480,8 @@ public class PackageManagerService extends IPackageManager.Stub
// for the uninstall-updates case and restricted profiles, remember the per-
// user handle installed state
int[] allUsers;
+ final int freezeUser;
+ final SparseArray<Pair<Integer, String>> enabledStateAndCallerPerUser;
/** enabled state of the uninstalled application */
synchronized (mLock) {
uninstalledPs = mSettings.getPackageLPr(packageName);
@@ -21539,16 +21526,23 @@ public class PackageManagerService extends IPackageManager.Stub
}
info.origUsers = uninstalledPs.queryInstalledUsers(allUsers, true);
- }
- final int freezeUser;
- if (isUpdatedSystemApp(uninstalledPs)
- && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
- // We're downgrading a system app, which will apply to all users, so
- // freeze them all during the downgrade
- freezeUser = UserHandle.USER_ALL;
- } else {
- freezeUser = removeUser;
+ if (isUpdatedSystemApp(uninstalledPs)
+ && ((deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0)) {
+ // We're downgrading a system app, which will apply to all users, so
+ // freeze them all during the downgrade
+ freezeUser = UserHandle.USER_ALL;
+ enabledStateAndCallerPerUser = new SparseArray<>();
+ for (int i = 0; i < allUsers.length; i++) {
+ PackageUserState userState = uninstalledPs.readUserState(allUsers[i]);
+ Pair<Integer, String> enabledStateAndCaller =
+ new Pair<>(userState.enabled, userState.lastDisableAppCaller);
+ enabledStateAndCallerPerUser.put(allUsers[i], enabledStateAndCaller);
+ }
+ } else {
+ freezeUser = removeUser;
+ enabledStateAndCallerPerUser = null;
+ }
}
synchronized (mInstallLock) {
@@ -21617,6 +21611,19 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
}
+ if (enabledStateAndCallerPerUser != null) {
+ synchronized (mLock) {
+ for (int i = 0; i < allUsers.length; i++) {
+ Pair<Integer, String> enabledStateAndCaller =
+ enabledStateAndCallerPerUser.get(allUsers[i]);
+ getPackageSetting(packageName)
+ .setEnabled(enabledStateAndCaller.first,
+ allUsers[i],
+ enabledStateAndCaller.second);
+ }
+ mSettings.writeAllUsersPackageRestrictionsLPr();
+ }
+ }
}
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
@@ -28141,8 +28148,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public void deleteOatArtifactsOfPackage(String packageName) {
- PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
+ public long deleteOatArtifactsOfPackage(String packageName) {
+ return PackageManagerService.this.deleteOatArtifactsOfPackage(packageName);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 49559f299fa0..1aa80a953d6c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -307,6 +307,8 @@ class PackageManagerShellCommand extends ShellCommand {
return runLogVisibility();
case "bypass-staged-installer-check":
return runBypassStagedInstallerCheck();
+ case "bypass-allowed-apex-update-check":
+ return runBypassAllowedApexUpdateCheck();
case "set-silent-updates-policy":
return runSetSilentUpdatesPolicy();
default: {
@@ -424,6 +426,20 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
+ private int runBypassAllowedApexUpdateCheck() {
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ mInterface.getPackageInstaller()
+ .bypassNextAllowedApexUpdateCheck(Boolean.parseBoolean(getNextArg()));
+ return 0;
+ } catch (RemoteException e) {
+ pw.println("Failure ["
+ + e.getClass().getName() + " - "
+ + e.getMessage() + "]");
+ return -1;
+ }
+ }
+
private int uninstallSystemUpdates(String packageName) {
final PrintWriter pw = getOutPrintWriter();
boolean failedUninstalls = false;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 4a68b7606c60..c842ff1b11a5 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -955,8 +955,7 @@ public class StagingManager {
continue;
} else if (isApexSessionFailed(apexSession)) {
hasFailedApexSession = true;
- String errorMsg = "APEX activation failed. Check logcat messages from apexd "
- + "for more information.";
+ String errorMsg = "APEX activation failed. " + apexSession.errorMessage;
if (!TextUtils.isEmpty(apexSession.crashingNativeProcess)) {
prepareForLoggingApexdRevert(session, apexSession.crashingNativeProcess);
errorMsg = "Session reverted due to crashing native process: "
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 83d4ce7ff057..b26b6940a1af 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -22,6 +22,7 @@ import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILATI
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_APK_FALLBACK;
import static com.android.internal.art.ArtStatsLog.ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK;
+import android.os.SystemClock;
import android.util.Slog;
import android.util.jar.StrictJarFile;
@@ -288,7 +289,7 @@ public class ArtStatsLogUtils {
ART_DATUM_REPORTED__COMPILE_FILTER__ART_COMPILATION_FILTER_UNKNOWN),
COMPILATION_REASON_MAP.getOrDefault(compilationReason, ArtStatsLog.
ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN),
- /*timestamp_millis=*/ 0L,
+ /*timestamp_millis=*/ SystemClock.uptimeMillis(),
ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
kind,
value,
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index bad7e5c27b7b..dab980a9e4b2 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -641,7 +641,7 @@ final class DefaultPermissionGrantPolicy {
// Cell Broadcast Receiver
grantSystemFixedPermissionsToSystemPackage(pm,
getDefaultSystemHandlerActivityPackage(pm, Intents.SMS_CB_RECEIVED_ACTION, userId),
- userId, SMS_PERMISSIONS);
+ userId, SMS_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS);
// Carrier Provisioning Service
grantPermissionsToSystemPackage(pm,
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 a391dbc1fa47..38e9d3ec34e3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -5720,10 +5720,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean fromDatasource, int attributedOp) {
// Now let's check the identity chain...
final int op = AppOpsManager.permissionToOpCode(permission);
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
-
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -5879,9 +5877,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionChecker.PERMISSION_HARD_DENIED;
}
- final int attributionChainId = (startDataDelivery)
- ? sAttributionChainIds.incrementAndGet()
- : AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ final int attributionChainId =
+ getAttributionChainId(startDataDelivery, attributionSource);
AttributionSource current = attributionSource;
AttributionSource next = null;
@@ -6064,6 +6061,21 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ private static int getAttributionChainId(boolean startDataDelivery,
+ AttributionSource source) {
+ if (source == null || source.getNext() == null || !startDataDelivery) {
+ return AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
+ }
+ int attributionChainId = sAttributionChainIds.incrementAndGet();
+
+ // handle overflow
+ if (attributionChainId < 0) {
+ attributionChainId = 0;
+ sAttributionChainIds.set(0);
+ }
+ return attributionChainId;
+ }
+
private static @Nullable String resolvePackageName(@NonNull Context context,
@NonNull AttributionSource attributionSource) {
if (attributionSource.getPackageName() != null) {
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index 05879ec9545e..fad0aefd3c0a 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -28,6 +28,7 @@ import com.android.server.pm.PackageSetting;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
/**
* For use by {@link PackageSetting} to maintain functionality that used to exist in
@@ -110,6 +111,10 @@ public class PackageStateUnserialized {
this.overrideSeInfo = other.overrideSeInfo;
}
+ public @NonNull List<SharedLibraryInfo> getNonNativeUsesLibraryInfos() {
+ return getUsesLibraryInfos().stream()
+ .filter((l) -> !l.isNative()).collect(Collectors.toList());
+ }
// Code below generated by codegen v1.0.14.
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index ed4a7bf107d1..f72adb609f6f 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -961,11 +961,13 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
@Override
public boolean allocateSpaceForUpdate(String packageFile) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
if (!isUpdatableApexSupported()) {
Log.i(TAG, "Updatable Apex not supported, "
+ "allocateSpaceForUpdate does nothing.");
return true;
}
+ final long token = Binder.clearCallingIdentity();
try {
CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile);
ApexManager apexManager = ApexManager.getInstance();
@@ -975,6 +977,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
e.rethrowAsRuntimeException();
} catch (IOException | UnsupportedOperationException e) {
Slog.e(TAG, "Failed to reserve space for compressed apex: ", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
return false;
}
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index f7d61367c81e..95a06fcff734 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -453,6 +453,10 @@ public class Vcn extends Handler {
for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
}
+
+ // Update the mobile data state after updating the subscription snapshot as a change in
+ // subIds for a subGroup may affect the mobile data state.
+ handleMobileDataToggled();
}
private void handleMobileDataToggled() {
diff --git a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
index d439b94ec2fc..1d8c64bddd49 100644
--- a/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
+++ b/services/core/java/com/android/server/vibrator/StepToRampAdapter.java
@@ -22,6 +22,7 @@ import android.os.vibrator.RampSegment;
import android.os.vibrator.StepSegment;
import android.os.vibrator.VibrationEffectSegment;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -59,6 +60,7 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
convertStepsToRamps(segments);
int newRepeatIndex = addRampDownToZeroAmplitudeSegments(segments, repeatIndex);
newRepeatIndex = addRampDownToLoop(segments, newRepeatIndex);
+ newRepeatIndex = splitLongRampSegments(info, segments, newRepeatIndex);
return newRepeatIndex;
}
@@ -210,11 +212,70 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
return repeatIndex;
}
+ /**
+ * Split {@link RampSegment} entries that have duration longer than {@link
+ * VibratorInfo#getPwlePrimitiveDurationMax()}.
+ */
+ private int splitLongRampSegments(VibratorInfo info, List<VibrationEffectSegment> segments,
+ int repeatIndex) {
+ int maxDuration = info.getPwlePrimitiveDurationMax();
+ if (maxDuration <= 0) {
+ // No limit set to PWLE primitive duration.
+ return repeatIndex;
+ }
+
+ int segmentCount = segments.size();
+ for (int i = 0; i < segmentCount; i++) {
+ if (!(segments.get(i) instanceof RampSegment)) {
+ continue;
+ }
+ RampSegment ramp = (RampSegment) segments.get(i);
+ int splits = ((int) ramp.getDuration() + maxDuration - 1) / maxDuration;
+ if (splits <= 1) {
+ continue;
+ }
+ segments.remove(i);
+ segments.addAll(i, splitRampSegment(ramp, splits));
+ int addedSegments = splits - 1;
+ if (repeatIndex > i) {
+ repeatIndex += addedSegments;
+ }
+ i += addedSegments;
+ segmentCount += addedSegments;
+ }
+
+ return repeatIndex;
+ }
+
private static RampSegment apply(StepSegment segment) {
return new RampSegment(segment.getAmplitude(), segment.getAmplitude(),
segment.getFrequency(), segment.getFrequency(), (int) segment.getDuration());
}
+ private static List<RampSegment> splitRampSegment(RampSegment ramp, int splits) {
+ List<RampSegment> ramps = new ArrayList<>(splits);
+ long splitDuration = ramp.getDuration() / splits;
+ float previousAmplitude = ramp.getStartAmplitude();
+ float previousFrequency = ramp.getStartFrequency();
+ long accumulatedDuration = 0;
+
+ for (int i = 1; i < splits; i++) {
+ accumulatedDuration += splitDuration;
+ RampSegment rampSplit = new RampSegment(
+ previousAmplitude, interpolateAmplitude(ramp, accumulatedDuration),
+ previousFrequency, interpolateFrequency(ramp, accumulatedDuration),
+ (int) splitDuration);
+ ramps.add(rampSplit);
+ previousAmplitude = rampSplit.getEndAmplitude();
+ previousFrequency = rampSplit.getEndFrequency();
+ }
+
+ ramps.add(new RampSegment(previousAmplitude, ramp.getEndAmplitude(), previousFrequency,
+ ramp.getEndFrequency(), (int) (ramp.getDuration() - accumulatedDuration)));
+
+ return ramps;
+ }
+
private static RampSegment createRampDown(float amplitude, float frequency, long duration) {
return new RampSegment(amplitude, /* endAmplitude= */ 0, frequency, frequency,
(int) duration);
@@ -244,4 +305,19 @@ final class StepToRampAdapter implements VibrationEffectAdapters.SegmentsAdapter
}
return false;
}
+
+ private static float interpolateAmplitude(RampSegment ramp, long duration) {
+ return interpolate(ramp.getStartAmplitude(), ramp.getEndAmplitude(), duration,
+ ramp.getDuration());
+ }
+
+ private static float interpolateFrequency(RampSegment ramp, long duration) {
+ return interpolate(ramp.getStartFrequency(), ramp.getEndFrequency(), duration,
+ ramp.getDuration());
+ }
+
+ private static float interpolate(float start, float end, long duration, long totalDuration) {
+ float position = (float) duration / totalDuration;
+ return start + position * (end - start);
+ }
}
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index f756434e981a..885f0e4c78ab 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -353,6 +353,7 @@ final class VibrationSettings {
+ ", mLowPowerMode=" + mLowPowerMode
+ ", mZenMode=" + Settings.Global.zenModeToString(mZenMode)
+ ", mProcStatesCache=" + mUidObserver.mProcStatesCache
+ + ", mHapticChannelMaxVibrationAmplitude=" + getHapticChannelMaxVibrationAmplitude()
+ ", mHapticFeedbackIntensity="
+ intensityToString(getCurrentIntensity(VibrationAttributes.USAGE_TOUCH))
+ ", mHapticFeedbackDefaultIntensity="
@@ -411,6 +412,12 @@ final class VibrationSettings {
}
}
+ private float getHapticChannelMaxVibrationAmplitude() {
+ synchronized (mLock) {
+ return mVibrator == null ? Float.NaN : mVibrator.getHapticChannelMaximumAmplitude();
+ }
+ }
+
private int getSystemSetting(String settingName, int defaultValue) {
return Settings.System.getIntForUser(mContext.getContentResolver(),
settingName, defaultValue, UserHandle.USER_CURRENT);
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index 150fde99b706..45d511159e11 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -844,7 +844,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
public List<Step> play() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePrimitivesStep");
try {
- int segmentCount = effect.getSegments().size();
+ // Load the next PrimitiveSegments to create a single compose call to the vibrator,
+ // limited to the vibrator composition maximum size.
+ int limit = controller.getVibratorInfo().getCompositionSizeMax();
+ int segmentCount = limit > 0
+ ? Math.min(effect.getSegments().size(), segmentIndex + limit)
+ : effect.getSegments().size();
List<PrimitiveSegment> primitives = new ArrayList<>();
for (int i = segmentIndex; i < segmentCount; i++) {
VibrationEffectSegment segment = effect.getSegments().get(i);
@@ -896,7 +901,12 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
public List<Step> play() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "ComposePwleStep");
try {
- int segmentCount = effect.getSegments().size();
+ // Load the next RampSegments to create a single composePwle call to the vibrator,
+ // limited to the vibrator PWLE maximum size.
+ int limit = controller.getVibratorInfo().getPwleSizeMax();
+ int segmentCount = limit > 0
+ ? Math.min(effect.getSegments().size(), segmentIndex + limit)
+ : effect.getSegments().size();
List<RampSegment> pwles = new ArrayList<>();
for (int i = segmentIndex; i < segmentCount; i++) {
VibrationEffectSegment segment = effect.getSegments().get(i);
diff --git a/services/core/java/com/android/server/vibrator/VibratorController.java b/services/core/java/com/android/server/vibrator/VibratorController.java
index 5dceac2d066c..001d5c440d58 100644
--- a/services/core/java/com/android/server/vibrator/VibratorController.java
+++ b/services/core/java/com/android/server/vibrator/VibratorController.java
@@ -30,19 +30,24 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
import libcore.util.NativeAllocationRegistry;
/** Controls a single vibrator. */
final class VibratorController {
private static final String TAG = "VibratorController";
+ // TODO(b/167947076): load suggested range from config
+ private static final int SUGGESTED_FREQUENCY_SAFE_RANGE = 200;
private final Object mLock = new Object();
private final NativeWrapper mNativeWrapper;
- private final VibratorInfo mVibratorInfo;
+ private final VibratorInfo.Builder mVibratorInfoBuilder;
@GuardedBy("mLock")
+ private VibratorInfo mVibratorInfo;
+ @GuardedBy("mLock")
+ private boolean mVibratorInfoLoaded;
+ @GuardedBy("mLock")
private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners =
new RemoteCallbackList<>();
@GuardedBy("mLock")
@@ -66,10 +71,10 @@ final class VibratorController {
NativeWrapper nativeWrapper) {
mNativeWrapper = nativeWrapper;
mNativeWrapper.init(vibratorId, listener);
- // TODO(b/167947076): load suggested range from config
- mVibratorInfo = mNativeWrapper.getInfo(/* suggestedFrequencyRange= */ 200);
- Preconditions.checkNotNull(mVibratorInfo, "Failed to retrieve data for vibrator %d",
- vibratorId);
+ mVibratorInfoBuilder = new VibratorInfo.Builder(vibratorId);
+ mVibratorInfoLoaded = mNativeWrapper.getInfo(SUGGESTED_FREQUENCY_SAFE_RANGE,
+ mVibratorInfoBuilder);
+ mVibratorInfo = mVibratorInfoBuilder.build();
}
/** Register state listener for this vibrator. */
@@ -103,7 +108,15 @@ final class VibratorController {
/** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */
public VibratorInfo getVibratorInfo() {
- return mVibratorInfo;
+ synchronized (mLock) {
+ if (!mVibratorInfoLoaded) {
+ // Try to load the vibrator metadata that has failed in the last attempt.
+ mVibratorInfoLoaded = mNativeWrapper.getInfo(SUGGESTED_FREQUENCY_SAFE_RANGE,
+ mVibratorInfoBuilder);
+ mVibratorInfo = mVibratorInfoBuilder.build();
+ }
+ return mVibratorInfo;
+ }
}
/**
@@ -361,7 +374,8 @@ final class VibratorController {
private static native void alwaysOnDisable(long nativePtr, long id);
- private static native VibratorInfo getInfo(long nativePtr, float suggestedFrequencyRange);
+ private static native boolean getInfo(long nativePtr, float suggestedFrequencyRange,
+ VibratorInfo.Builder infoBuilder);
private long mNativePtr = 0;
@@ -428,9 +442,11 @@ final class VibratorController {
alwaysOnDisable(mNativePtr, id);
}
- /** Return device vibrator metadata. */
- public VibratorInfo getInfo(float suggestedFrequencyRange) {
- return getInfo(mNativePtr, suggestedFrequencyRange);
+ /**
+ * Loads device vibrator metadata and returns true if all metadata was loaded successfully.
+ */
+ public boolean getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder) {
+ return getInfo(mNativePtr, suggestedFrequencyRange, infoBuilder);
}
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 53f1035ee422..782e18b0250c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -129,7 +129,9 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -3140,7 +3142,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private void writeWallpaperAttributes(TypedXmlSerializer out, String tag,
+
+ @VisibleForTesting
+ void writeWallpaperAttributes(TypedXmlSerializer out, String tag,
WallpaperData wallpaper)
throws IllegalArgumentException, IllegalStateException, IOException {
if (DEBUG) {
@@ -3179,6 +3183,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
out.attributeInt(null, "colorValue" + i, wc.toArgb());
}
}
+
+ int allColorsCount = wallpaper.primaryColors.getAllColors().size();
+ out.attributeInt(null, "allColorsCount", allColorsCount);
+ if (allColorsCount > 0) {
+ int index = 0;
+ for (Map.Entry<Integer, Integer> entry : wallpaper.primaryColors.getAllColors()
+ .entrySet()) {
+ out.attributeInt(null, "allColorsValue" + index, entry.getKey());
+ out.attributeInt(null, "allColorsPopulation" + index, entry.getValue());
+ index++;
+ }
+ }
+
out.attributeInt(null, "colorHints", wallpaper.primaryColors.getColorHints());
}
@@ -3410,7 +3427,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
}
}
- private void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper,
+ @VisibleForTesting
+ void parseWallpaperAttributes(TypedXmlPullParser parser, WallpaperData wallpaper,
boolean keepDimensionHints) throws XmlPullParserException {
final int id = parser.getAttributeInt(null, "id", -1);
if (id != -1) {
@@ -3437,7 +3455,17 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0);
wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0);
int colorsCount = getAttributeInt(parser, "colorsCount", 0);
- if (colorsCount > 0) {
+ int allColorsCount = getAttributeInt(parser, "allColorsCount", 0);
+ if (allColorsCount > 0) {
+ Map<Integer, Integer> allColors = new HashMap<>(allColorsCount);
+ for (int i = 0; i < allColorsCount; i++) {
+ int colorInt = getAttributeInt(parser, "allColorsValue" + i, 0);
+ int population = getAttributeInt(parser, "allColorsPopulation" + i, 0);
+ allColors.put(colorInt, population);
+ }
+ int colorHints = getAttributeInt(parser, "colorHints", 0);
+ wallpaper.primaryColors = new WallpaperColors(allColors, colorHints);
+ } else if (colorsCount > 0) {
Color primary = null, secondary = null, tertiary = null;
for (int i = 0; i < colorsCount; i++) {
Color color = Color.valueOf(getAttributeInt(parser, "colorValue" + i, 0));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 55d1920681c5..0ad8782cea4f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -38,6 +38,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -277,6 +278,7 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
+import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
import android.service.voice.IVoiceInteractionSession;
@@ -327,6 +329,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.PendingIntentRecord;
+import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.uri.NeededUriGrants;
@@ -677,8 +680,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private boolean mInSizeCompatModeForBounds = false;
// Whether the aspect ratio restrictions applied to the activity bounds in applyAspectRatio().
- // TODO(b/182268157): Aspect ratio can also be applie in resolveFixedOrientationConfiguration
- // but that isn't reflected in this boolean.
private boolean mIsAspectRatioApplied = false;
// Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
@@ -1788,17 +1789,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/**
* Evaluate the theme for a starting window.
+ * @param prev Previous activity which may have a starting window.
* @param originalTheme The original theme which read from activity or application.
* @param replaceTheme The replace theme which requested from starter.
* @return Resolved theme.
*/
- private int evaluateStartingWindowTheme(String pkg, int originalTheme, int replaceTheme) {
+ private int evaluateStartingWindowTheme(ActivityRecord prev, String pkg, int originalTheme,
+ int replaceTheme) {
// Skip if the package doesn't want a starting window.
- if (!validateStartingWindowTheme(pkg, originalTheme)) {
+ if (!validateStartingWindowTheme(prev, pkg, originalTheme)) {
return 0;
}
int selectedTheme = originalTheme;
- if (replaceTheme != 0 && validateStartingWindowTheme(pkg, replaceTheme)) {
+ if (replaceTheme != 0 && validateStartingWindowTheme(prev, pkg, replaceTheme)) {
// allow to replace theme
selectedTheme = replaceTheme;
}
@@ -1835,7 +1838,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return LAUNCH_SOURCE_TYPE_APPLICATION;
}
- private boolean validateStartingWindowTheme(String pkg, int theme) {
+ private boolean validateStartingWindowTheme(ActivityRecord prev, String pkg, int theme) {
// If this is a translucent window, then don't show a starting window -- the current
// effect (a full-screen opaque starting window that fades away to the real contents
// when it is ready) does not work for this.
@@ -1872,7 +1875,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
if (windowDisableStarting && !launchedFromSystemSurface()) {
- return false;
+ // Check if previous activity can transfer the starting window to this activity.
+ return prev != null && prev.getActivityType() == ACTIVITY_TYPE_STANDARD
+ && prev.mTransferringSplashScreenState == TRANSFER_SPLASH_SCREEN_IDLE
+ && (prev.mStartingData != null
+ || (prev.mStartingWindow != null && prev.mStartingSurface != null));
}
return true;
}
@@ -4873,6 +4880,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
true /* activityChange */, true /* updateOomAdj */,
true /* addPendingTopUid */);
}
+ final ContentCaptureManagerInternal contentCaptureService =
+ LocalServices.getService(ContentCaptureManagerInternal.class);
+ if (contentCaptureService != null) {
+ contentCaptureService.notifyActivityEvent(mUserId, mActivityComponent,
+ ActivityEvent.TYPE_ACTIVITY_STARTED);
+ }
break;
case PAUSED:
mAtmService.updateBatteryStats(this, false);
@@ -6278,15 +6291,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mSplashScreenStyleEmpty = shouldUseEmptySplashScreen(sourceRecord);
- final int resolvedTheme = evaluateStartingWindowTheme(packageName, theme,
+ final int resolvedTheme = evaluateStartingWindowTheme(prev, packageName, theme,
splashScreenTheme);
+ final boolean activityCreated =
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal();
+ // If this activity is just created and all activities below are finish, treat this
+ // scenario as warm launch.
+ final boolean newSingleActivity = !newTask && !activityCreated
+ && task.getActivity((r) -> !r.finishing && r != this) == null;
+
final boolean shown = addStartingWindow(packageName, resolvedTheme,
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
- prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
- allowTaskSnapshot(),
- mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
- mSplashScreenStyleEmpty);
+ prev != null ? prev.appToken : null,
+ newTask || newSingleActivity, taskSwitch, isProcessRunning(),
+ allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
}
@@ -7266,41 +7285,48 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
- final int parentWidth = parentBounds.width();
- final int parentHeight = parentBounds.height();
- float aspect = Math.max(parentWidth, parentHeight)
- / (float) Math.min(parentWidth, parentHeight);
+ final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
+ final Rect containingBounds = new Rect();
+ final Rect containingAppBounds = new Rect();
+ // Need to shrink the containing bounds into a square because the parent orientation does
+ // not match the activity requested orientation.
+ if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+ // Shrink height to match width. Position height within app bounds.
+ final int bottom = Math.min(parentAppBounds.top + parentBounds.width(),
+ parentAppBounds.bottom);
+ containingBounds.set(parentBounds.left, parentAppBounds.top, parentBounds.right,
+ bottom);
+ containingAppBounds.set(parentAppBounds.left, parentAppBounds.top,
+ parentAppBounds.right, bottom);
+ } else {
+ // Shrink width to match height. Position width within app bounds.
+ final int right = Math.min(parentAppBounds.left + parentBounds.height(),
+ parentAppBounds.right);
+ containingBounds.set(parentAppBounds.left, parentBounds.top, right,
+ parentBounds.bottom);
+ containingAppBounds.set(parentAppBounds.left, parentAppBounds.top, right,
+ parentAppBounds.bottom);
+ }
+
+ Rect mTmpFullBounds = new Rect(resolvedBounds);
+ resolvedBounds.set(containingBounds);
// Override from config_fixedOrientationLetterboxAspectRatio or via ADB with
// set-fixed-orientation-letterbox-aspect-ratio.
final float letterboxAspectRatioOverride =
mWmService.mLetterboxConfiguration.getFixedOrientationLetterboxAspectRatio();
- aspect = letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
- ? letterboxAspectRatioOverride : aspect;
-
- // Adjust the fixed orientation letterbox bounds to fit the app request aspect ratio in
- // order to use the extra available space.
- final float maxAspectRatio = info.getMaxAspectRatio();
- final float minAspectRatio = info.getMinAspectRatio();
- if (aspect > maxAspectRatio && maxAspectRatio != 0) {
- aspect = maxAspectRatio;
- } else if (aspect < minAspectRatio) {
- aspect = minAspectRatio;
- }
-
- // Store the current bounds to be able to revert to size compat mode values below if needed.
- Rect mTmpFullBounds = new Rect(resolvedBounds);
+ final float desiredAspectRatio =
+ letterboxAspectRatioOverride > MIN_FIXED_ORIENTATION_LETTERBOX_ASPECT_RATIO
+ ? letterboxAspectRatioOverride : computeAspectRatio(parentBounds);
+ // Apply aspect ratio to resolved bounds
+ mIsAspectRatioApplied = applyAspectRatio(resolvedBounds, containingAppBounds,
+ containingBounds, desiredAspectRatio, true);
+
+ // Vertically center if orientation is landscape. Bounds will later be horizontally centered
+ // in {@link updateResolvedBoundsHorizontalPosition()} regardless of orientation.
if (forcedOrientation == ORIENTATION_LANDSCAPE) {
- final int height = (int) Math.rint(parentWidth / aspect);
- final int top = parentBounds.centerY() - height / 2;
- resolvedBounds.set(parentBounds.left, top, parentBounds.right, top + height);
- } else {
- final int width = (int) Math.rint(parentHeight / aspect);
- final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
- final int left = width <= parentAppBounds.width()
- // Avoid overlapping with the horizontal decor area when possible.
- ? parentAppBounds.left : parentBounds.centerX() - width / 2;
- resolvedBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+ final int offsetY = parentBounds.centerY() - resolvedBounds.centerY();
+ resolvedBounds.offset(0, offsetY);
}
if (mCompatDisplayInsets != null) {
@@ -7342,8 +7368,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// then they should be aligned later in #updateResolvedBoundsHorizontalPosition().
if (!mTmpBounds.isEmpty()) {
resolvedBounds.set(mTmpBounds);
- // Exclude the horizontal decor area.
- resolvedBounds.left = parentAppBounds.left;
}
if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) {
// Compute the configuration based on the resolved bounds. If aspect ratio doesn't
@@ -7404,13 +7428,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mIsAspectRatioApplied =
applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds);
}
- // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in
- // the container app bounds. Otherwise the entire container bounds are available.
- final boolean fillContainer = resolvedBounds.equals(containingBounds);
- if (!fillContainer) {
- // The horizontal position should not cover insets.
- resolvedBounds.left = containingAppBounds.left;
- }
// Use resolvedBounds to compute other override configurations such as appBounds. The bounds
// are calculated in compat container space. The actual position on screen will be applied
@@ -7477,6 +7494,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Align to top of parent (bounds) - this is a UX choice and exclude the horizontal decor
// if needed. Horizontal position is adjusted in updateResolvedBoundsHorizontalPosition.
// Above coordinates are in "@" space, now place "*" and "#" to screen space.
+ final boolean fillContainer = resolvedBounds.equals(containingBounds);
final int screenPosX = fillContainer ? containerBounds.left : containerAppBounds.left;
final int screenPosY = containerBounds.top;
if (screenPosX != 0 || screenPosY != 0) {
@@ -7713,6 +7731,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return true;
}
+ private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
+ Rect containingBounds) {
+ return applyAspectRatio(outBounds, containingAppBounds, containingBounds,
+ 0 /* desiredAspectRatio */, false /* fixedOrientationLetterboxed */);
+ }
+
/**
* Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is
* made to outBounds.
@@ -7721,17 +7745,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
// TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
private boolean applyAspectRatio(Rect outBounds, Rect containingAppBounds,
- Rect containingBounds) {
+ Rect containingBounds, float desiredAspectRatio, boolean fixedOrientationLetterboxed) {
final float maxAspectRatio = info.getMaxAspectRatio();
final Task rootTask = getRootTask();
final float minAspectRatio = info.getMinAspectRatio();
if (task == null || rootTask == null
- || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets())
- || (maxAspectRatio == 0 && minAspectRatio == 0)
+ || (inMultiWindowMode() && !shouldCreateCompatDisplayInsets()
+ && !fixedOrientationLetterboxed)
+ || (maxAspectRatio < 1 && minAspectRatio < 1 && desiredAspectRatio < 1)
|| isInVrUiMode(getConfiguration())) {
- // We don't enforce aspect ratio if the activity task is in multiwindow unless it
- // is in size-compat mode. We also don't set it if we are in VR mode.
+ // We don't enforce aspect ratio if the activity task is in multiwindow unless it is in
+ // size-compat mode or is letterboxed from fixed orientation. We also don't set it if we
+ // are in VR mode.
return false;
}
@@ -7739,20 +7765,30 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final int containingAppHeight = containingAppBounds.height();
final float containingRatio = computeAspectRatio(containingAppBounds);
+ if (desiredAspectRatio < 1) {
+ desiredAspectRatio = containingRatio;
+ }
+
+ if (maxAspectRatio >= 1 && desiredAspectRatio > maxAspectRatio) {
+ desiredAspectRatio = maxAspectRatio;
+ } else if (minAspectRatio >= 1 && desiredAspectRatio < minAspectRatio) {
+ desiredAspectRatio = minAspectRatio;
+ }
+
int activityWidth = containingAppWidth;
int activityHeight = containingAppHeight;
- if (containingRatio > maxAspectRatio && maxAspectRatio != 0) {
+ if (containingRatio > desiredAspectRatio) {
if (containingAppWidth < containingAppHeight) {
// Width is the shorter side, so we use that to figure-out what the max. height
// should be given the aspect ratio.
- activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth * desiredAspectRatio) + 0.5f);
} else {
// Height is the shorter side, so we use that to figure-out what the max. width
// should be given the aspect ratio.
- activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight * desiredAspectRatio) + 0.5f);
}
- } else if (containingRatio < minAspectRatio) {
+ } else if (containingRatio < desiredAspectRatio) {
boolean adjustWidth;
switch (getRequestedConfigurationOrientation()) {
case ORIENTATION_LANDSCAPE:
@@ -7780,9 +7816,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
break;
}
if (adjustWidth) {
- activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f);
+ activityWidth = (int) ((activityHeight / desiredAspectRatio) + 0.5f);
} else {
- activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f);
+ activityHeight = (int) ((activityWidth / desiredAspectRatio) + 0.5f);
}
}
@@ -7806,6 +7842,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
outBounds.set(containingBounds.left, containingBounds.top, right, bottom);
+ // If the bounds are restricted by fixed aspect ratio, then out bounds should be put in the
+ // container app bounds. Otherwise the entire container bounds are available.
+ if (!outBounds.equals(containingBounds)) {
+ // The horizontal position should not cover insets.
+ outBounds.left = containingAppBounds.left;
+ }
+
return true;
}
diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java
index 0ec01422474a..2ea043a5c623 100644
--- a/services/core/java/com/android/server/wm/CompatModePackages.java
+++ b/services/core/java/com/android/server/wm/CompatModePackages.java
@@ -75,10 +75,18 @@ public final class CompatModePackages {
* CompatModePackages#DOWNSCALED is the gatekeeper of all per-app buffer downscaling
* changes. Disabling this change will prevent the following scaling factors from working:
* CompatModePackages#DOWNSCALE_90
+ * CompatModePackages#DOWNSCALE_85
* CompatModePackages#DOWNSCALE_80
+ * CompatModePackages#DOWNSCALE_75
* CompatModePackages#DOWNSCALE_70
+ * CompatModePackages#DOWNSCALE_65
* CompatModePackages#DOWNSCALE_60
+ * CompatModePackages#DOWNSCALE_55
* CompatModePackages#DOWNSCALE_50
+ * CompatModePackages#DOWNSCALE_45
+ * CompatModePackages#DOWNSCALE_40
+ * CompatModePackages#DOWNSCALE_35
+ * CompatModePackages#DOWNSCALE_30
*
* If CompatModePackages#DOWNSCALED is enabled for an app package, then the app will be forcibly
* resized to the highest enabled scaling factor e.g. 80% if both 80% and 70% were enabled.
@@ -100,6 +108,16 @@ public final class CompatModePackages {
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_85 for a package will force the app to assume it's
+ * running on a display with 85% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_85 = 189969734L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_80 for a package will force the app to assume it's
* running on a display with 80% the vertical and horizontal resolution of the real display.
*/
@@ -110,6 +128,16 @@ public final class CompatModePackages {
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_75 for a package will force the app to assume it's
+ * running on a display with 75% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_75 = 189969779L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_70 for a package will force the app to assume it's
* running on a display with 70% the vertical and horizontal resolution of the real display.
*/
@@ -120,6 +148,16 @@ public final class CompatModePackages {
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_65 for a package will force the app to assume it's
+ * running on a display with 65% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_65 = 189969744L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_60 for a package will force the app to assume it's
* running on a display with 60% the vertical and horizontal resolution of the real display.
*/
@@ -130,6 +168,16 @@ public final class CompatModePackages {
/**
* With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_55 for a package will force the app to assume it's
+ * running on a display with 55% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_55 = 189970036L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
* CompatModePackages#DOWNSCALE_50 for a package will force the app to assume it's
* running on a display with 50% vertical and horizontal resolution of the real display.
*/
@@ -139,6 +187,46 @@ public final class CompatModePackages {
public static final long DOWNSCALE_50 = 176926741L;
/**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_45 for a package will force the app to assume it's
+ * running on a display with 45% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_45 = 189969782L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_40 for a package will force the app to assume it's
+ * running on a display with 40% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_40 = 189970038L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_35 for a package will force the app to assume it's
+ * running on a display with 35% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_35 = 189969749L;
+
+ /**
+ * With CompatModePackages#DOWNSCALED enabled, subsequently enabling change-id
+ * CompatModePackages#DOWNSCALE_30 for a package will force the app to assume it's
+ * running on a display with 30% the vertical and horizontal resolution of the real display.
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ public static final long DOWNSCALE_30 = 189970040L;
+
+ /**
* On Android TV applications that target pre-S are not expecting to receive a Window larger
* than 1080p, so if needed we are downscaling their Windows to 1080p.
* However, applications that target S and greater release version are expected to be able to
@@ -291,18 +379,42 @@ public final class CompatModePackages {
if (CompatChanges.isChangeEnabled(DOWNSCALE_90, packageName, userHandle)) {
return 1f / 0.9f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_85, packageName, userHandle)) {
+ return 1f / 0.85f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_80, packageName, userHandle)) {
return 1f / 0.8f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_75, packageName, userHandle)) {
+ return 1f / 0.75f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_70, packageName, userHandle)) {
return 1f / 0.7f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_65, packageName, userHandle)) {
+ return 1f / 0.65f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_60, packageName, userHandle)) {
return 1f / 0.6f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_55, packageName, userHandle)) {
+ return 1f / 0.55f;
+ }
if (CompatChanges.isChangeEnabled(DOWNSCALE_50, packageName, userHandle)) {
return 1f / 0.5f;
}
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_45, packageName, userHandle)) {
+ return 1f / 0.45f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_40, packageName, userHandle)) {
+ return 1f / 0.4f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_35, packageName, userHandle)) {
+ return 1f / 0.35f;
+ }
+ if (CompatChanges.isChangeEnabled(DOWNSCALE_30, packageName, userHandle)) {
+ return 1f / 0.3f;
+ }
}
if (mService.mHasLeanbackFeature) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ea80b8bb5286..bc2556a5a497 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
@@ -220,6 +221,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
// transaction from the global transaction.
private final SurfaceControl.Transaction mDisplayTransaction;
+ // The tag for the token to put root tasks on the displays to sleep.
+ private static final String DISPLAY_OFF_SLEEP_TOKEN_TAG = "Display-off";
+
/** The token acquirer to put root tasks on the displays to sleep */
final ActivityTaskManagerInternal.SleepTokenAcquirer mDisplayOffTokenAcquirer;
@@ -449,7 +453,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mService = service.mAtmService;
mTaskSupervisor = mService.mTaskSupervisor;
mTaskSupervisor.mRootWindowContainer = this;
- mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl("Display-off");
+ mDisplayOffTokenAcquirer = mService.new SleepTokenAcquirerImpl(DISPLAY_OFF_SLEEP_TOKEN_TAG);
}
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -2653,12 +2657,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.d(TAG, "Remove non-exist sleep token: " + token + " from " + Debug.getCallers(6));
}
mSleepTokens.remove(token.mHashKey);
-
final DisplayContent display = getDisplayContent(token.mDisplayId);
if (display != null) {
display.mAllSleepTokens.remove(token);
if (display.mAllSleepTokens.isEmpty()) {
mService.updateSleepIfNeededLocked();
+ if (token.mTag.equals(DISPLAY_OFF_SLEEP_TOKEN_TAG)) {
+ display.mSkipAppTransitionAnimation = true;
+ }
}
}
}
@@ -3383,6 +3389,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
*/
void lockAllProfileTasks(@UserIdInt int userId) {
forAllLeafTasks(task -> {
+ final ActivityRecord top = task.topRunningActivity();
+ if (top != null && !top.finishing
+ && ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER.equals(top.intent.getAction())
+ && top.packageName.equals(
+ mService.getSysUiServiceComponentLocked().getPackageName())) {
+ // Do nothing since the task is already secure by sysui.
+ return;
+ }
+
if (task.getActivity(activity -> !activity.finishing && activity.mUserId == userId)
!= null) {
mService.getTaskChangeNotificationController().notifyTaskProfileLocked(
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 565f99f80890..325f10f65af2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -974,10 +974,7 @@ class Task extends WindowContainer<WindowContainer> {
}
void removeIfPossible(String reason) {
- final boolean isRootTask = isRootTask();
- if (!isRootTask) {
- mAtmService.getLockTaskController().clearLockedTask(this);
- }
+ mAtmService.getLockTaskController().clearLockedTask(this);
if (shouldDeferRemoval()) {
if (DEBUG_ROOT_TASK) Slog.i(TAG,
"removeTask:" + reason + " deferring removing taskId=" + mTaskId);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e9dd521670a9..2c8fcebdd50f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2463,6 +2463,17 @@ public class WindowManagerService extends IWindowManager.Stub
configChanged = displayContent.updateOrientation();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ final DisplayInfo rotatedDisplayInfo =
+ win.mToken.getFixedRotationTransformDisplayInfo();
+ if (rotatedDisplayInfo != null) {
+ outSurfaceControl.setTransformHint(rotatedDisplayInfo.rotation);
+ } else {
+ // We have to update the transform hint of display here, but we need to get if from
+ // SurfaceFlinger, so set it as rotation of display for most cases, then
+ // SurfaceFlinger would still update the transform hint of display in next frame.
+ outSurfaceControl.setTransformHint(displayContent.getDisplayInfo().rotation);
+ }
+
if (toBeDisplayed && win.mIsWallpaper) {
displayContent.mWallpaperController.updateWallpaperOffset(win, false /* sync */);
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9a6e4448966d..4471f6c91190 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -683,8 +683,9 @@ class WindowStateAnimator {
}
// We don't apply animation for application main window here since this window type
- // should be controlled by AppWindowToken in general.
- if (mAttrType != TYPE_BASE_APPLICATION) {
+ // should be controlled by ActivityRecord in general. Wallpaper is also excluded because
+ // WallpaperController should handle it.
+ if (mAttrType != TYPE_BASE_APPLICATION && !mIsWallpaper) {
applyAnimationLocked(transit, true);
}
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index 698e3f75d0ed..9029fe7cca66 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -41,8 +41,18 @@ static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnComplete;
static jclass sFrequencyMappingClass;
static jmethodID sFrequencyMappingCtor;
-static jclass sVibratorInfoClass;
-static jmethodID sVibratorInfoCtor;
+static struct {
+ jmethodID setCapabilities;
+ jmethodID setSupportedEffects;
+ jmethodID setSupportedBraking;
+ jmethodID setPwlePrimitiveDurationMax;
+ jmethodID setPwleSizeMax;
+ jmethodID setSupportedPrimitive;
+ jmethodID setPrimitiveDelayMax;
+ jmethodID setCompositionSizeMax;
+ jmethodID setQFactor;
+ jmethodID setFrequencyMapping;
+} sVibratorInfoBuilderClassInfo;
static struct {
jfieldID id;
jfieldID scale;
@@ -352,68 +362,88 @@ static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr,
wrapper->halCall<void>(alwaysOnDisableFn, "alwaysOnDisable");
}
-static jobject vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr,
- jfloat suggestedSafeRange) {
+static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jfloat suggestedSafeRange, jobject vibratorInfoBuilder) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorGetInfo failed because native wrapper was not initialized");
- return nullptr;
+ return JNI_FALSE;
}
vibrator::Info info = wrapper->getVibratorInfo();
- jlong capabilities =
- static_cast<jlong>(info.capabilities.valueOr(vibrator::Capabilities::NONE));
- jfloat minFrequency = static_cast<jfloat>(info.minFrequency.valueOr(NAN));
- jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN));
- jfloat frequencyResolution = static_cast<jfloat>(info.frequencyResolution.valueOr(NAN));
- jfloat qFactor = static_cast<jfloat>(info.qFactor.valueOr(NAN));
- jintArray supportedEffects = nullptr;
- jintArray supportedBraking = nullptr;
- jintArray supportedPrimitives = nullptr;
- jintArray primitiveDurations = nullptr;
- jfloatArray maxAmplitudes = nullptr;
-
+ if (info.capabilities.isOk()) {
+ env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities,
+ static_cast<jlong>(info.capabilities.value()));
+ }
if (info.supportedEffects.isOk()) {
std::vector<aidl::Effect> effects = info.supportedEffects.value();
- supportedEffects = env->NewIntArray(effects.size());
+ jintArray supportedEffects = env->NewIntArray(effects.size());
env->SetIntArrayRegion(supportedEffects, 0, effects.size(),
reinterpret_cast<jint*>(effects.data()));
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setSupportedEffects, supportedEffects);
}
if (info.supportedBraking.isOk()) {
std::vector<aidl::Braking> braking = info.supportedBraking.value();
- supportedBraking = env->NewIntArray(braking.size());
+ jintArray supportedBraking = env->NewIntArray(braking.size());
env->SetIntArrayRegion(supportedBraking, 0, braking.size(),
reinterpret_cast<jint*>(braking.data()));
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setSupportedBraking, supportedBraking);
}
- if (info.supportedPrimitives.isOk()) {
- std::vector<aidl::CompositePrimitive> primitives = info.supportedPrimitives.value();
- supportedPrimitives = env->NewIntArray(primitives.size());
- env->SetIntArrayRegion(supportedPrimitives, 0, primitives.size(),
- reinterpret_cast<jint*>(primitives.data()));
+ if (info.pwlePrimitiveDurationMax.isOk()) {
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax,
+ static_cast<jint>(info.pwlePrimitiveDurationMax.value().count()));
+ }
+ if (info.pwleSizeMax.isOk()) {
+ // Use (pwleMaxSize - 1) to account for a possible extra braking segment added by the
+ // vibratorPerformPwleEffect method.
+ env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setPwleSizeMax,
+ static_cast<jint>(info.pwleSizeMax.value() - 1));
}
- if (info.primitiveDurations.isOk()) {
- std::vector<int32_t> durations;
- for (auto duration : info.primitiveDurations.value()) {
- durations.push_back(duration.count());
+ if (info.supportedPrimitives.isOk()) {
+ auto durations = info.primitiveDurations.valueOr({});
+ for (auto& primitive : info.supportedPrimitives.value()) {
+ auto primitiveIdx = static_cast<size_t>(primitive);
+ auto duration = durations.size() > primitiveIdx ? durations[primitiveIdx].count() : 0;
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setSupportedPrimitive,
+ static_cast<jint>(primitive), static_cast<jint>(duration));
}
- primitiveDurations = env->NewIntArray(durations.size());
- env->SetIntArrayRegion(primitiveDurations, 0, durations.size(),
- reinterpret_cast<jint*>(durations.data()));
}
+ if (info.primitiveDelayMax.isOk()) {
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax,
+ static_cast<jint>(info.primitiveDelayMax.value().count()));
+ }
+ if (info.compositionSizeMax.isOk()) {
+ env->CallObjectMethod(vibratorInfoBuilder,
+ sVibratorInfoBuilderClassInfo.setCompositionSizeMax,
+ static_cast<jint>(info.compositionSizeMax.value()));
+ }
+ if (info.qFactor.isOk()) {
+ env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setQFactor,
+ static_cast<jfloat>(info.qFactor.value()));
+ }
+
+ jfloat minFrequency = static_cast<jfloat>(info.minFrequency.valueOr(NAN));
+ jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN));
+ jfloat frequencyResolution = static_cast<jfloat>(info.frequencyResolution.valueOr(NAN));
+ jfloatArray maxAmplitudes = nullptr;
if (info.maxAmplitudes.isOk()) {
std::vector<float> amplitudes = info.maxAmplitudes.value();
maxAmplitudes = env->NewFloatArray(amplitudes.size());
env->SetFloatArrayRegion(maxAmplitudes, 0, amplitudes.size(),
reinterpret_cast<jfloat*>(amplitudes.data()));
}
-
jobject frequencyMapping = env->NewObject(sFrequencyMappingClass, sFrequencyMappingCtor,
minFrequency, resonantFrequency, frequencyResolution,
suggestedSafeRange, maxAmplitudes);
+ env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyMapping,
+ frequencyMapping);
- return env->NewObject(sVibratorInfoClass, sVibratorInfoCtor, wrapper->getVibratorId(),
- capabilities, supportedEffects, supportedBraking, supportedPrimitives,
- primitiveDurations, qFactor, frequencyMapping);
+ return info.checkAndLogFailure("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE;
}
static const JNINativeMethod method_table[] = {
@@ -433,7 +463,7 @@ static const JNINativeMethod method_table[] = {
{"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
{"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
{"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
- {"getInfo", "(JF)Landroid/os/VibratorInfo;", (void*)vibratorGetInfo},
+ {"getInfo", "(JFLandroid/os/VibratorInfo$Builder;)Z", (void*)vibratorGetInfo},
};
int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
@@ -459,11 +489,38 @@ int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env
sFrequencyMappingClass = static_cast<jclass>(env->NewGlobalRef(frequencyMappingClass));
sFrequencyMappingCtor = GetMethodIDOrDie(env, sFrequencyMappingClass, "<init>", "(FFFF[F)V");
- jclass vibratorInfoClass = FindClassOrDie(env, "android/os/VibratorInfo");
- sVibratorInfoClass = (jclass)env->NewGlobalRef(vibratorInfoClass);
- sVibratorInfoCtor =
- GetMethodIDOrDie(env, sVibratorInfoClass, "<init>",
- "(IJ[I[I[I[IFLandroid/os/VibratorInfo$FrequencyMapping;)V");
+ jclass vibratorInfoBuilderClass = FindClassOrDie(env, "android/os/VibratorInfo$Builder");
+ sVibratorInfoBuilderClassInfo.setCapabilities =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCapabilities",
+ "(J)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setSupportedEffects =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedEffects",
+ "([I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setSupportedBraking =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedBraking",
+ "([I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwlePrimitiveDurationMax",
+ "(I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setPwleSizeMax =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwleSizeMax",
+ "(I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setSupportedPrimitive =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedPrimitive",
+ "(II)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPrimitiveDelayMax",
+ "(I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setCompositionSizeMax =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCompositionSizeMax",
+ "(I)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setQFactor =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setQFactor",
+ "(F)Landroid/os/VibratorInfo$Builder;");
+ sVibratorInfoBuilderClassInfo.setFrequencyMapping =
+ GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setFrequencyMapping",
+ "(Landroid/os/VibratorInfo$FrequencyMapping;)"
+ "Landroid/os/VibratorInfo$Builder;");
return jniRegisterNativeMethods(env,
"com/android/server/vibrator/VibratorController$NativeWrapper",
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 3e2e37c834f1..82aaa61527d1 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -77,6 +77,10 @@
<xs:annotation name="final"/>
</xs:element>
<xs:element name="timing" type="hbmTiming" minOccurs="1" maxOccurs="1"/>
+ <xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:all>
<xs:attribute name="enabled" type="xs:boolean" use="optional"/>
</xs:complexType>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index d40854a87453..6e2e3625f60c 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -44,10 +44,12 @@ package com.android.server.display.config {
ctor public HighBrightnessMode();
method public boolean getEnabled();
method @NonNull public final java.math.BigDecimal getMinimumLux_all();
+ method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all();
method public com.android.server.display.config.HbmTiming getTiming_all();
method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
method public void setEnabled(boolean);
method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
+ method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange);
method public void setTiming_all(com.android.server.display.config.HbmTiming);
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index dd864aed4e8e..a822257e1a74 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -51,7 +51,6 @@ java_library {
// All the classes in netd_aidl_interface must be jarjar so they do not conflict with the
// classes generated by netd_aidl_interfaces-platform-java above.
"netd_aidl_interface-V3-java",
- "netlink-client",
"networkstack-client",
"modules-utils-build_system",
],
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index e99113d1296f..acf50b4569c6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -323,6 +323,8 @@ public class DeviceIdleControllerTest {
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
doNothing().when(mWakeLock).acquire();
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
+ doNothing().when(mAlarmManager)
+ .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any());
doReturn(mock(Sensor.class)).when(mSensorManager)
.getDefaultSensor(eq(Sensor.TYPE_SIGNIFICANT_MOTION), eq(true));
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
@@ -1043,24 +1045,28 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l == mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
// Should just alternate between IDLE and IDLE_MAINTENANCE now.
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET));
+ longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET));
+ longThat(l -> l >= mConstants.LIGHT_IDLE_MAINTENANCE_MIN_BUDGET),
+ longThat(l -> l == mConstants.FLEX_TIME_SHORT));
// Test that motion doesn't reset the idle timeout.
mDeviceIdleController.handleMotionDetectedLocked(50, "test");
@@ -1068,7 +1074,8 @@ public class DeviceIdleControllerTest {
mDeviceIdleController.stepLightIdleStateLocked("testing");
verifyLightStateConditions(LIGHT_STATE_IDLE);
inOrder.verify(mDeviceIdleController).scheduleLightAlarmLocked(
- longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT));
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT),
+ longThat(l -> l > mConstants.LIGHT_IDLE_TIMEOUT_INITIAL_FLEX));
}
///////////////// EXIT conditions ///////////////////
@@ -1824,9 +1831,9 @@ public class DeviceIdleControllerTest {
.forClass(AlarmManager.OnAlarmListener.class);
final ArgumentCaptor<AlarmManager.OnAlarmListener> motionRegistrationAlarmListener =
ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(), eq("DeviceIdleController.motion"),
- motionAlarmListener.capture(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
+ eq("DeviceIdleController.motion"), motionAlarmListener.capture(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
motionRegistrationAlarmListener.capture(), any());
@@ -1900,9 +1907,9 @@ public class DeviceIdleControllerTest {
mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager)
- .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
ArgumentCaptor<TriggerEventListener> listenerCaptor =
@@ -1944,9 +1951,9 @@ public class DeviceIdleControllerTest {
mInjector.nowElapsed += mConstants.QUICK_DOZE_DELAY_TIMEOUT;
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
- doNothing().when(mAlarmManager)
- .set(anyInt(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
- doNothing().when(mAlarmManager).set(anyInt(), anyLong(),
+ doNothing().when(mAlarmManager).setWindow(
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
ArgumentCaptor<SensorEventListener> listenerCaptor =
diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index da0b83ec819c..28fcaee79572 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -21,7 +21,6 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import static com.google.common.truth.Truth.assertThat;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.provider.DeviceConfig;
import androidx.test.core.app.ApplicationProvider;
@@ -63,7 +62,6 @@ public class PlatformLoggerTest {
public void testCreateExtraStatsLocked_samplingIntervalNotSet_returnsDefault() {
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -96,8 +94,7 @@ public class PlatformLoggerTest {
int putDocumentSamplingInterval = 1;
int batchCallSamplingInterval = 2;
PlatformLogger logger = new PlatformLogger(
- ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL), mAppSearchConfig);
+ ApplicationProvider.getApplicationContext(), mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
AppSearchConfig.KEY_MIN_TIME_INTERVAL_BETWEEN_SAMPLES_MILLIS,
@@ -143,7 +140,6 @@ public class PlatformLoggerTest {
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -162,7 +158,6 @@ public class PlatformLoggerTest {
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -186,7 +181,6 @@ public class PlatformLoggerTest {
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
@@ -214,7 +208,6 @@ public class PlatformLoggerTest {
final String testPackageName = "packageName";
PlatformLogger logger = new PlatformLogger(
ApplicationProvider.getApplicationContext(),
- UserHandle.of(UserHandle.USER_NULL),
mAppSearchConfig);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH,
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
index b480f24fb371..5e219a25ed9a 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/GnssGeofenceProxyTest.java
@@ -18,6 +18,7 @@ package com.android.server.location.gnss;
import static com.google.common.truth.Truth.assertThat;
+import android.content.Context;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -49,6 +50,7 @@ public class GnssGeofenceProxyTest {
private static final int NOTIFICATION_RESPONSIVENESS = 0;
private static final int UNKNOWN_TIMER = 0;
+ private @Mock Context mContext;
private @Mock GnssConfiguration mMockConfiguration;
private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
@@ -63,7 +65,7 @@ public class GnssGeofenceProxyTest {
GnssNative.setGnssHalForTest(mFakeHal);
GnssNative gnssNative = Objects.requireNonNull(
- GnssNative.create(new TestInjector(), mMockConfiguration));
+ GnssNative.create(new TestInjector(mContext), mMockConfiguration));
gnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
mTestProvider = new GnssGeofenceProxy(gnssNative);
gnssNative.register();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
index 3d0378170c94..d728451d92b9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeAppOpsHelper.java
@@ -29,9 +29,10 @@ import java.util.HashMap;
public class FakeAppOpsHelper extends AppOpsHelper {
private static class AppOp {
- private boolean mAllowed = true;
- private boolean mStarted = false;
- private int mNoteCount = 0;
+ AppOp() {}
+ boolean mAllowed = true;
+ boolean mStarted = false;
+ int mNoteCount = 0;
}
private final HashMap<String, SparseArray<AppOp>> mAppOps;
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
index f1099f0e8184..cd70020f5c28 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeSettingsHelper.java
@@ -29,8 +29,8 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
- * Version of AppOpsHelper for testing. Settings are initialized to reasonable defaults (location is
- * enabled by default).
+ * Version of SettingsHelper for testing. Settings are initialized to reasonable defaults (location
+ * is enabled by default).
*/
public class FakeSettingsHelper extends SettingsHelper {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
index ae70dadba041..bd24cfd78a2c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/TestInjector.java
@@ -16,9 +16,14 @@
package com.android.server.location.injector;
+import android.content.Context;
+
+import com.android.server.location.settings.FakeLocationSettings;
+
public class TestInjector implements Injector {
private final FakeUserInfoHelper mUserInfoHelper;
+ private final FakeLocationSettings mLocationSettings;
private final FakeAlarmHelper mAlarmHelper;
private final FakeAppOpsHelper mAppOpsHelper;
private final FakeLocationPermissionsHelper mLocationPermissionsHelper;
@@ -32,8 +37,9 @@ public class TestInjector implements Injector {
private final FakeEmergencyHelper mEmergencyHelper;
private final LocationUsageLogger mLocationUsageLogger;
- public TestInjector() {
+ public TestInjector(Context context) {
mUserInfoHelper = new FakeUserInfoHelper();
+ mLocationSettings = new FakeLocationSettings(context);
mAlarmHelper = new FakeAlarmHelper();
mAppOpsHelper = new FakeAppOpsHelper();
mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
@@ -54,6 +60,11 @@ public class TestInjector implements Injector {
}
@Override
+ public FakeLocationSettings getLocationSettings() {
+ return mLocationSettings;
+ }
+
+ @Override
public FakeAlarmHelper getAlarmHelper() {
return mAlarmHelper;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 6bc3b6041070..f703e2e59181 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -19,6 +19,8 @@ package com.android.server.location.provider;
import static android.app.AppOpsManager.OP_FINE_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationRequest.PASSIVE_INTERVAL;
import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
@@ -56,6 +58,8 @@ import static org.mockito.MockitoAnnotations.initMocks;
import static org.testng.Assert.assertThrows;
import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.location.ILocationCallback;
import android.location.ILocationListener;
import android.location.LastLocationRequest;
@@ -82,6 +86,7 @@ import android.util.Log;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.location.injector.FakeUserInfoHelper;
@@ -139,6 +144,10 @@ public class LocationProviderManagerTest {
@Mock
private Context mContext;
@Mock
+ private Resources mResources;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
private PowerManager mPowerManager;
@Mock
private PowerManager.WakeLock mWakeLock;
@@ -161,20 +170,28 @@ public class LocationProviderManagerTest {
LocalServices.addService(LocationManagerInternal.class, mInternal);
doReturn("android").when(mContext).getPackageName();
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
- mInjector = new TestInjector();
+ mInjector = new TestInjector(mContext);
mInjector.getUserInfoHelper().startUser(OTHER_USER);
mPassive = new PassiveLocationProviderManager(mContext, mInjector);
mPassive.startManager(null);
mPassive.setRealProvider(new PassiveLocationProvider(mContext));
+ createManager(NAME);
+ }
+
+ private void createManager(String name) {
+ mStateChangedListener = mock(LocationProviderManager.StateChangedListener.class);
+
mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
mProvider.setProviderAllowed(true);
- mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
+ mManager = new LocationProviderManager(mContext, mInjector, name, mPassive);
mManager.startManager(mStateChangedListener);
mManager.setRealProvider(mProvider);
}
@@ -1017,6 +1034,95 @@ public class LocationProviderManagerTest {
}
@Test
+ public void testProviderRequest_AdasGnssBypass() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(5)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(1)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_AdasGnssBypass_ProviderDisabled() {
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(1)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(5)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_AdasGnssBypass_ProviderDisabled_AdasDisabled() {
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ createManager(GPS_PROVIDER);
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = new LocationRequest.Builder(5)
+ .setLocationSettingsIgnored(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = new LocationRequest.Builder(1)
+ .setAdasGnssBypass(true)
+ .setWorkSource(WORK_SOURCE)
+ .build();
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getLocationSettings().updateUserSettings(IDENTITY.getUserId(),
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().isActive()).isTrue();
+ assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
+ assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
+ }
+
+ @Test
public void testProviderRequest_BatterySaver_ScreenOnOff() {
mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode(
LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
index 04e0151e619a..63996f0e021c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
+import android.content.Context;
import android.location.Location;
import android.location.LocationResult;
import android.location.provider.ProviderRequest;
@@ -58,6 +59,7 @@ public class StationaryThrottlingLocationProviderTest {
private TestInjector mInjector;
private FakeProvider mDelegateProvider;
+ private @Mock Context mContext;
private @Mock AbstractLocationProvider.Listener mListener;
private @Mock FakeProvider.FakeProviderInterface mDelegate;
@@ -72,7 +74,7 @@ public class StationaryThrottlingLocationProviderTest {
mRandom = new Random(seed);
- mInjector = new TestInjector();
+ mInjector = new TestInjector(mContext);
mDelegateProvider = new FakeProvider(mDelegate);
mProvider = new StationaryThrottlingLocationProvider("test_provider", mInjector,
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java b/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java
new file mode 100644
index 000000000000..4d46abaa6733
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/settings/FakeLocationSettings.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import java.io.File;
+
+public class FakeLocationSettings extends LocationSettings {
+
+ public FakeLocationSettings(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected File getUserSettingsDir(int userId) {
+ return ApplicationProvider.getApplicationContext().getCacheDir();
+ }
+
+ @Override
+ protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
+ return new FakeLocationUserSettingsStore(userId, file);
+ }
+
+ private class FakeLocationUserSettingsStore extends LocationUserSettingsStore {
+
+ FakeLocationUserSettingsStore(int userId, File file) {
+ super(userId, file);
+ }
+
+ @Override
+ protected void onChange(LocationUserSettings oldSettings,
+ LocationUserSettings newSettings) {
+ fireListeners(mUserId, oldSettings, newSettings);
+ }
+ }
+}
+
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java b/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java
new file mode 100644
index 000000000000..4b6c79b954cd
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/settings/LocationSettingsTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location.settings;
+
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
+
+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.eq;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.File;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationSettingsTest {
+
+ private @Mock Context mContext;
+ private @Mock Resources mResources;
+ private @Mock PackageManager mPackageManager;
+
+ private LocationSettings mLocationSettings;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ doReturn(mResources).when(mContext).getResources();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+
+ resetLocationSettings();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mLocationSettings.deleteFiles();
+ }
+
+ private void resetLocationSettings() {
+ mLocationSettings = new LocationSettings(mContext) {
+ @Override
+ protected File getUserSettingsDir(int userId) {
+ return ApplicationProvider.getApplicationContext().getCacheDir();
+ }
+ };
+ }
+
+ @Test
+ public void testLoadDefaults() {
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ assertThat(mLocationSettings.getUserSettings(2).isAdasGnssLocationEnabled()).isFalse();
+ }
+
+ @Test
+ public void testUpdate() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ }
+
+ @Test
+ public void testSerialization() throws Exception {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+
+ mLocationSettings.flushFiles();
+ resetLocationSettings();
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
+ }
+
+ @Test
+ public void testListeners() {
+ doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+ LocationSettings.LocationUserSettingsListener listener = mock(
+ LocationSettings.LocationUserSettingsListener.class);
+
+ mLocationSettings.registerLocationUserSettingsListener(listener);
+
+ ArgumentCaptor<LocationUserSettings> oldCaptor = ArgumentCaptor.forClass(
+ LocationUserSettings.class);
+ ArgumentCaptor<LocationUserSettings> newCaptor = ArgumentCaptor.forClass(
+ LocationUserSettings.class);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ verify(listener, timeout(500).times(1)).onLocationUserSettingsChanged(eq(1),
+ oldCaptor.capture(), newCaptor.capture());
+ assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
+ assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
+
+ oldCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
+ newCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(false));
+ verify(listener, timeout(500).times(2)).onLocationUserSettingsChanged(eq(1),
+ oldCaptor.capture(), newCaptor.capture());
+ assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
+ assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
+
+ mLocationSettings.unregisterLocationUserSettingsListener(listener);
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ verify(listener, after(500).times(2)).onLocationUserSettingsChanged(anyInt(), any(), any());
+ }
+
+ @Test
+ public void testNonAutomotive() {
+ doReturn(false).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
+ doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
+
+ LocationSettings.LocationUserSettingsListener listener = mock(
+ LocationSettings.LocationUserSettingsListener.class);
+ mLocationSettings.registerLocationUserSettingsListener(listener);
+
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ mLocationSettings.updateUserSettings(1,
+ settings -> settings.withAdasGnssLocationEnabled(true));
+ assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
+ verify(listener, after(500).never()).onLocationUserSettingsChanged(anyInt(), any(), any());
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
index 7d628be571a9..68570ffc6fce 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java
@@ -286,6 +286,7 @@ public class StagingManagerTest {
ApexSessionInfo activationFailed = new ApexSessionInfo();
activationFailed.sessionId = 1543;
activationFailed.isActivationFailed = true;
+ activationFailed.errorMessage = "Failed for test";
ApexSessionInfo staged = new ApexSessionInfo();
staged.sessionId = 101;
@@ -309,8 +310,8 @@ public class StagingManagerTest {
assertThat(apexSession1.getErrorCode())
.isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
- assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. Check logcat "
- + "messages from apexd for more information.");
+ assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. "
+ + "Failed for test");
assertThat(apexSession2.getErrorCode())
.isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED);
diff --git a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
index 5a42c4bc7f3a..53483f6d70bc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/wallpaper/WallpaperManagerServiceTests.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -57,6 +58,9 @@ import android.service.wallpaper.WallpaperService;
import android.testing.TestableContext;
import android.util.Log;
import android.util.SparseArray;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
import android.view.Display;
import androidx.test.filters.FlakyTest;
@@ -82,9 +86,12 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.quality.Strictness;
+import org.xmlpull.v1.XmlPullParserException;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
/**
* Tests for the {@link WallpaperManagerService} class.
@@ -355,6 +362,31 @@ public class WallpaperManagerServiceTests {
verifyDisplayData();
}
+ @Test
+ public void testXmlSerializationRoundtrip() {
+ WallpaperData systemWallpaperData = mService.getCurrentWallpaperData(FLAG_SYSTEM, 0);
+ try {
+ TypedXmlSerializer serializer = Xml.newBinarySerializer();
+ serializer.setOutput(new ByteArrayOutputStream(), StandardCharsets.UTF_8.name());
+ serializer.startDocument(StandardCharsets.UTF_8.name(), true);
+ mService.writeWallpaperAttributes(serializer, "wp", systemWallpaperData);
+ } catch (IOException e) {
+ fail("exception occurred while writing system wallpaper attributes");
+ }
+
+ WallpaperData shouldMatchSystem = new WallpaperData(systemWallpaperData.userId,
+ systemWallpaperData.wallpaperFile.getParentFile(),
+ systemWallpaperData.wallpaperFile.getAbsolutePath(),
+ systemWallpaperData.cropFile.getAbsolutePath());
+ try {
+ TypedXmlPullParser parser = Xml.newBinaryPullParser();
+ mService.parseWallpaperAttributes(parser, shouldMatchSystem, true);
+ } catch (XmlPullParserException e) {
+ fail("exception occurred while parsing wallpaper");
+ }
+ assertEquals(systemWallpaperData.primaryColors, shouldMatchSystem.primaryColors);
+ }
+
// Verify that after continue switch user from userId 0 to lastUserId, the wallpaper data for
// non-current user must not bind to wallpaper service.
private void verifyNoConnectionBeforeLastUser(int lastUserId) {
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index aadaba4d2fce..3c10789bc792 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -42,7 +42,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.compatibility.common.util.SystemUtil;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.visibilitystore.VisibilityStoreImpl;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -67,7 +67,7 @@ public class AppSearchImplPlatformTest {
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
private AppSearchImpl mAppSearchImpl;
- private VisibilityStore mVisibilityStore;
+ private VisibilityStoreImpl mVisibilityStore;
private int mGlobalQuerierUid;
@Before
@@ -93,7 +93,7 @@ public class AppSearchImplPlatformTest {
// Give ourselves global query permissions
mAppSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- mVisibilityStore = VisibilityStore.create(mAppSearchImpl, mContext);
+ mVisibilityStore = VisibilityStoreImpl.create(mAppSearchImpl, mContext);
mGlobalQuerierUid =
mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
@@ -127,8 +127,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
@@ -159,8 +159,8 @@ public class AppSearchImplPlatformTest {
new AppSearchSchema.Builder("schema1").build(),
new AppSearchSchema.Builder("schema2").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
@@ -233,8 +233,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("schema1"),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.singletonList("schema1"),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
@@ -263,8 +263,8 @@ public class AppSearchImplPlatformTest {
"database",
/*schemas=*/ Collections.emptyList(),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
/*schemaVersion=*/ 0);
@@ -292,8 +292,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("schema1").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
@@ -327,8 +327,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
@@ -355,8 +355,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.singletonList("Schema"),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.singletonList("Schema"),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
@@ -370,7 +370,7 @@ public class AppSearchImplPlatformTest {
}
@Test
- public void testSetSchema_defaultNotPackageAccessible() throws Exception {
+ public void testSetSchema_defaultNotVisibleToPackages() throws Exception {
String packageName = "com.package";
// Make sure package doesn't global query privileges
@@ -384,8 +384,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*schemaVersion=*/ 0);
assertThat(mVisibilityStore
@@ -399,7 +399,7 @@ public class AppSearchImplPlatformTest {
}
@Test
- public void testSetSchema_packageAccessible() throws Exception {
+ public void testSetSchema_visibleToPackages() throws Exception {
// Values for a "foo" client
String packageNameFoo = "packageFoo";
byte[] sha256CertFoo = new byte[] {10};
@@ -423,8 +423,8 @@ public class AppSearchImplPlatformTest {
"database",
Collections.singletonList(new AppSearchSchema.Builder("Schema").build()),
mVisibilityStore,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"Schema",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index f032402f47a0..02bb168dbde6 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -22,7 +22,7 @@ import static com.android.server.appsearch.external.localstorage.util.PrefixUtil
import static com.google.common.truth.Truth.assertThat;
-import static org.testng.Assert.expectThrows;
+import static org.junit.Assert.assertThrows;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
@@ -34,6 +34,7 @@ import android.app.appsearch.SetSchemaResponse;
import android.app.appsearch.StorageInfo;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
+import android.os.Process;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -55,7 +56,6 @@ import com.android.server.appsearch.proto.SearchSpecProto;
import com.android.server.appsearch.proto.StatusProto;
import com.android.server.appsearch.proto.StringIndexingConfig;
import com.android.server.appsearch.proto.TermMatchType;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -391,7 +391,7 @@ public class AppSearchImplTest {
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
- expectThrows(
+ assertThrows(
AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -416,7 +416,7 @@ public class AppSearchImplTest {
DocumentProto.Builder actualDocument = documentProto.toBuilder();
AppSearchException e =
- expectThrows(
+ assertThrows(
AppSearchException.class, () -> removePrefixesFromDocument(actualDocument));
assertThat(e).hasMessageThat().contains("Found unexpected multiple prefix names");
}
@@ -431,8 +431,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -480,8 +480,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -499,7 +499,7 @@ public class AppSearchImplTest {
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
- VisibilityStore.NO_OP_UID,
+ Process.INVALID_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).hasSize(1);
@@ -513,7 +513,7 @@ public class AppSearchImplTest {
.setSchema(context.getPackageName() + "$database1/Type1")
.build();
AppSearchException e =
- expectThrows(
+ assertThrows(
AppSearchException.class,
() -> PrefixUtil.getPrefix(invalidDoc.getNamespace()));
assertThat(e)
@@ -538,10 +538,8 @@ public class AppSearchImplTest {
assertThat(initStats.hasDeSync()).isFalse();
assertThat(initStats.getDocumentStoreRecoveryCause())
.isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
- // TODO(b/187879464): There should not be a recovery here, but icing lib reports one if the
- // doc had no tokens. Once the mentioned bug is fixed, uncomment this.
- // assertThat(initStats.getIndexRestorationCause())
- // .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
+ assertThat(initStats.getIndexRestorationCause())
+ .isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
assertThat(initStats.getSchemaStoreRecoveryCause())
.isEqualTo(InitializeStats.RECOVERY_CAUSE_NONE);
assertThat(initStats.getDocumentStoreDataStatus())
@@ -558,7 +556,7 @@ public class AppSearchImplTest {
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
- VisibilityStore.NO_OP_UID,
+ Process.INVALID_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).isEmpty();
@@ -569,8 +567,8 @@ public class AppSearchImplTest {
"database1",
Collections.singletonList(new AppSearchSchema.Builder("Type1").build()),
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -585,7 +583,7 @@ public class AppSearchImplTest {
new SearchSpec.Builder().addFilterSchemas("Type1").build(),
context.getPackageName(),
/*visibilityStore=*/ null,
- VisibilityStore.NO_OP_UID,
+ Process.INVALID_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(results.getResults()).hasSize(1);
@@ -604,8 +602,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -638,8 +636,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
mAppSearchImpl.setSchema(
@@ -647,8 +645,8 @@ public class AppSearchImplTest {
"database2",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -692,8 +690,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -734,8 +732,8 @@ public class AppSearchImplTest {
"database1",
schema1,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -747,8 +745,8 @@ public class AppSearchImplTest {
"database2",
schema2,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -790,8 +788,8 @@ public class AppSearchImplTest {
"database1",
schema1,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -803,8 +801,8 @@ public class AppSearchImplTest {
"database2",
schema2,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -851,7 +849,7 @@ public class AppSearchImplTest {
searchSpec,
/*callerPackageName=*/ "",
/*visibilityStore=*/ null,
- VisibilityStore.NO_OP_UID,
+ Process.INVALID_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null);
assertThat(searchResultPage.getResults()).isEmpty();
@@ -893,8 +891,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -938,8 +936,8 @@ public class AppSearchImplTest {
"database1",
oldSchemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -954,8 +952,8 @@ public class AppSearchImplTest {
"database1",
newSchemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
/*version=*/ 0);
assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Text");
@@ -977,8 +975,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1010,8 +1008,8 @@ public class AppSearchImplTest {
"database1",
finalSchemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1024,8 +1022,8 @@ public class AppSearchImplTest {
"database1",
finalSchemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
/*version=*/ 0);
@@ -1062,8 +1060,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
mAppSearchImpl.setSchema(
@@ -1071,8 +1069,8 @@ public class AppSearchImplTest {
"database2",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1111,8 +1109,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
/*version=*/ 0);
@@ -1156,8 +1154,8 @@ public class AppSearchImplTest {
"database",
schema,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1218,8 +1216,8 @@ public class AppSearchImplTest {
"database",
schema,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
mAppSearchImpl.setSchema(
@@ -1227,8 +1225,8 @@ public class AppSearchImplTest {
"database",
schema,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1273,8 +1271,8 @@ public class AppSearchImplTest {
"database1",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
assertThat(mAppSearchImpl.getPackageToDatabases())
@@ -1287,8 +1285,8 @@ public class AppSearchImplTest {
"database2",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
assertThat(mAppSearchImpl.getPackageToDatabases())
@@ -1301,8 +1299,8 @@ public class AppSearchImplTest {
"database1",
Collections.singletonList(new AppSearchSchema.Builder("schema").build()),
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
assertThat(mAppSearchImpl.getPackageToDatabases())
@@ -1360,8 +1358,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1511,8 +1509,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1534,8 +1532,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1550,8 +1548,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1599,8 +1597,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1622,8 +1620,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1644,8 +1642,8 @@ public class AppSearchImplTest {
"database1",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
mAppSearchImpl.setSchema(
@@ -1653,8 +1651,8 @@ public class AppSearchImplTest {
"database2",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1700,15 +1698,15 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
appSearchImpl.close();
// Check all our public APIs
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.setSchema(
@@ -1716,15 +1714,15 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0));
- expectThrows(
+ assertThrows(
IllegalStateException.class, () -> appSearchImpl.getSchema("package", "database"));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.putDocument(
@@ -1733,13 +1731,13 @@ public class AppSearchImplTest {
new GenericDocument.Builder<>("namespace", "id", "type").build(),
/*logger=*/ null));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.getDocument(
"package", "database", "namespace", "id", Collections.emptyMap()));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.query(
@@ -1749,7 +1747,7 @@ public class AppSearchImplTest {
new SearchSpec.Builder().build(),
/*logger=*/ null));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.globalQuery(
@@ -1757,19 +1755,19 @@ public class AppSearchImplTest {
new SearchSpec.Builder().build(),
"package",
/*visibilityStore=*/ null,
- VisibilityStore.NO_OP_UID,
+ Process.INVALID_UID,
/*callerHasSystemAccess=*/ false,
/*logger=*/ null));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() -> appSearchImpl.getNextPage(/*nextPageToken=*/ 1L));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() -> appSearchImpl.invalidateNextPageToken(/*nextPageToken=*/ 1L));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.reportUsage(
@@ -1780,7 +1778,7 @@ public class AppSearchImplTest {
/*usageTimestampMillis=*/ 1000L,
/*systemUsage=*/ false));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.remove(
@@ -1790,7 +1788,7 @@ public class AppSearchImplTest {
"id",
/*removeStatsBuilder=*/ null));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() ->
appSearchImpl.removeByQuery(
@@ -1800,15 +1798,15 @@ public class AppSearchImplTest {
new SearchSpec.Builder().build(),
/*removeStatsBuilder=*/ null));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() -> appSearchImpl.getStorageInfoForPackage("package"));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() -> appSearchImpl.getStorageInfoForDatabase("package", "database"));
- expectThrows(
+ assertThrows(
IllegalStateException.class,
() -> appSearchImpl.persistToDisk(PersistType.Code.FULL));
}
@@ -1827,8 +1825,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1866,8 +1864,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1892,7 +1890,7 @@ public class AppSearchImplTest {
// Delete the first document
appSearchImpl.remove("package", "database", "namespace1", "id1", /*statsBuilder=*/ null);
appSearchImpl.persistToDisk(PersistType.Code.LITE);
- expectThrows(
+ assertThrows(
AppSearchException.class,
() ->
appSearchImpl.getDocument(
@@ -1909,7 +1907,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- expectThrows(
+ assertThrows(
AppSearchException.class,
() ->
appSearchImpl2.getDocument(
@@ -1938,8 +1936,8 @@ public class AppSearchImplTest {
"database",
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
@@ -1972,7 +1970,7 @@ public class AppSearchImplTest {
.build(),
/*statsBuilder=*/ null);
appSearchImpl.persistToDisk(PersistType.Code.LITE);
- expectThrows(
+ assertThrows(
AppSearchException.class,
() ->
appSearchImpl.getDocument(
@@ -1989,7 +1987,7 @@ public class AppSearchImplTest {
// Only the second document should be retrievable from another instance.
AppSearchImpl appSearchImpl2 =
AppSearchImpl.create(appsearchDir, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- expectThrows(
+ assertThrows(
AppSearchException.class,
() ->
appSearchImpl2.getDocument(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index f20e8c6d13a9..9b75561fd2ec 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -25,6 +25,7 @@ import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
+import android.app.appsearch.exceptions.AppSearchException;
import com.android.server.appsearch.external.localstorage.stats.CallStats;
import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
@@ -32,17 +33,24 @@ import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
import com.android.server.appsearch.proto.DeleteStatsProto;
+import com.android.server.appsearch.proto.DocumentProto;
import com.android.server.appsearch.proto.InitializeStatsProto;
import com.android.server.appsearch.proto.PutDocumentStatsProto;
+import com.android.server.appsearch.proto.PutResultProto;
import com.android.server.appsearch.proto.QueryStatsProto;
import com.android.server.appsearch.proto.ScoringSpecProto;
+import com.android.server.appsearch.proto.StatusProto;
import com.android.server.appsearch.proto.TermMatchType;
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import java.io.File;
import java.util.Collections;
import java.util.List;
@@ -279,7 +287,7 @@ public class AppSearchLoggerTest {
// Testing actual logging
//
@Test
- public void testLoggingStats_initialize() throws Exception {
+ public void testLoggingStats_initializeWithoutDocuments_success() throws Exception {
// Create an unused AppSearchImpl to generated an InitializeStats.
InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
AppSearchImpl.create(mTemporaryFolder.newFolder(), initStatsBuilder, ALWAYS_OPTIMIZE);
@@ -295,25 +303,139 @@ public class AppSearchLoggerTest {
.isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE);
assertThat(iStats.getDocumentCount()).isEqualTo(0);
assertThat(iStats.getSchemaTypeCount()).isEqualTo(0);
+ assertThat(iStats.hasReset()).isEqualTo(false);
+ assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
}
@Test
- public void testLoggingStats_putDocument() throws Exception {
- // Insert schema
+ public void testLoggingStats_initializeWithDocuments_success() throws Exception {
final String testPackageName = "testPackage";
final String testDatabase = "testDatabase";
+ final File folder = mTemporaryFolder.newFolder();
+
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(folder, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
List<AppSearchSchema> schemas =
- Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ appSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
+ GenericDocument doc2 = new GenericDocument.Builder<>("namespace", "id2", "Type1").build();
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc2, mLogger);
+ appSearchImpl.close();
+
+ // Create another appsearchImpl on the same folder
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ AppSearchImpl.create(folder, initStatsBuilder, ALWAYS_OPTIMIZE);
+ InitializeStats iStats = initStatsBuilder.build();
+
+ assertThat(iStats).isNotNull();
+ assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ // Total latency captured in LocalStorage
+ assertThat(iStats.getTotalLatencyMillis()).isEqualTo(0);
+ assertThat(iStats.hasDeSync()).isFalse();
+ assertThat(iStats.getNativeLatencyMillis()).isGreaterThan(0);
+ assertThat(iStats.getDocumentStoreDataStatus())
+ .isEqualTo(InitializeStatsProto.DocumentStoreDataStatus.NO_DATA_LOSS_VALUE);
+ assertThat(iStats.getDocumentCount()).isEqualTo(2);
+ assertThat(iStats.getSchemaTypeCount()).isEqualTo(2);
+ assertThat(iStats.hasReset()).isEqualTo(false);
+ assertThat(iStats.getResetStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
+ }
+
+ @Test
+ public void testLoggingStats_initialize_failure() throws Exception {
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final File folder = mTemporaryFolder.newFolder();
+
+ AppSearchImpl appSearchImpl =
+ AppSearchImpl.create(folder, /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
+
+ List<AppSearchSchema> schemas =
+ ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ appSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ // Insert a valid doc
+ GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
+ appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
+
+ // Insert the invalid doc with an invalid namespace right into icing
+ DocumentProto invalidDoc =
+ DocumentProto.newBuilder()
+ .setNamespace("invalidNamespace")
+ .setUri("id2")
+ .setSchema(String.format("%s$%s/Type1", testPackageName, testDatabase))
+ .build();
+ PutResultProto putResultProto = appSearchImpl.mIcingSearchEngineLocked.put(invalidDoc);
+ assertThat(putResultProto.getStatus().getCode()).isEqualTo(StatusProto.Code.OK);
+ appSearchImpl.close();
+
+ // Create another appsearchImpl on the same folder
+ InitializeStats.Builder initStatsBuilder = new InitializeStats.Builder();
+ AppSearchImpl.create(folder, initStatsBuilder, ALWAYS_OPTIMIZE);
+ InitializeStats iStats = initStatsBuilder.build();
+
+ // Some of other fields are already covered by AppSearchImplTest#testReset()
+ assertThat(iStats).isNotNull();
+ assertThat(iStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_INTERNAL_ERROR);
+ assertThat(iStats.hasReset()).isTrue();
+ }
+
+ @Test
+ public void testLoggingStats_putDocument_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ AppSearchSchema testSchema =
+ new AppSearchSchema.Builder("type")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(
+ AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
mAppSearchImpl.setSchema(
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
- GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
+
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "type")
+ .setPropertyString("subject", "testPut example1")
+ .build();
mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger);
@@ -322,43 +444,119 @@ public class AppSearchLoggerTest {
assertThat(pStats.getPackageName()).isEqualTo(testPackageName);
assertThat(pStats.getDatabase()).isEqualTo(testDatabase);
assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
- // The rest of native stats have been tested in testCopyNativeStats
+ // The latency related native stats have been tested in testCopyNativeStats
assertThat(pStats.getNativeDocumentSizeBytes()).isGreaterThan(0);
+ assertThat(pStats.getNativeNumTokensIndexed()).isGreaterThan(0);
}
@Test
- public void testLoggingStats_search() throws Exception {
+ public void testLoggingStats_putDocument_failure() throws Exception {
// Insert schema
final String testPackageName = "testPackage";
final String testDatabase = "testDatabase";
- List<AppSearchSchema> schemas =
- Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ AppSearchSchema testSchema =
+ new AppSearchSchema.Builder("type")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(
+ AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
mAppSearchImpl.setSchema(
testPackageName,
testDatabase,
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
- GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
- mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger);
+ GenericDocument document =
+ new GenericDocument.Builder<>("namespace", "id", "type")
+ .setPropertyString("nonExist", "testPut example1")
+ .build();
+
+ // We mainly want to check the status code in stats. So we don't need to inspect the
+ // exception here.
+ Assert.assertThrows(
+ AppSearchException.class,
+ () -> mAppSearchImpl.putDocument(testPackageName, testDatabase, document, mLogger));
+
+ PutDocumentStats pStats = mLogger.mPutDocumentStats;
+ assertThat(pStats).isNotNull();
+ assertThat(pStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(pStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(pStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ }
+
+ @Test
+ public void testLoggingStats_search_success() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ AppSearchSchema testSchema =
+ new AppSearchSchema.Builder("type")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(
+ AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ List<AppSearchSchema> schemas = Collections.singletonList(testSchema);
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+ GenericDocument document1 =
+ new GenericDocument.Builder<>("namespace", "id1", "type")
+ .setPropertyString("subject", "testPut example1")
+ .build();
+ GenericDocument document2 =
+ new GenericDocument.Builder<>("namespace", "id2", "type")
+ .setPropertyString("subject", "testPut example2")
+ .build();
+ GenericDocument document3 =
+ new GenericDocument.Builder<>("namespace", "id3", "type")
+ .setPropertyString("subject", "testPut 3")
+ .build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document1, mLogger);
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document2, mLogger);
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document3, mLogger);
// No query filters specified. package2 should only get its own documents back.
SearchSpec searchSpec =
- new SearchSpec.Builder().setTermMatch(TermMatchType.Code.PREFIX_VALUE).build();
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP)
+ .build();
+ String queryStr = "testPut e";
SearchResultPage searchResultPage =
mAppSearchImpl.query(
- testPackageName,
- testDatabase,
- /*QueryExpression=*/ "",
- searchSpec,
- /*logger=*/ mLogger);
+ testPackageName, testDatabase, queryStr, searchSpec, /*logger=*/ mLogger);
- assertThat(searchResultPage.getResults()).hasSize(1);
- assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document);
+ assertThat(searchResultPage.getResults()).hasSize(2);
+ // The ranking strategy is LIFO
+ assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
+ assertThat(searchResultPage.getResults().get(1).getGenericDocument()).isEqualTo(document1);
SearchStats sStats = mLogger.mSearchStats;
@@ -368,17 +566,59 @@ public class AppSearchLoggerTest {
assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
assertThat(sStats.getTotalLatencyMillis()).isGreaterThan(0);
assertThat(sStats.getVisibilityScope()).isEqualTo(SearchStats.VISIBILITY_SCOPE_LOCAL);
- assertThat(sStats.getTermCount()).isEqualTo(0);
- // assertThat(sStats.getNativeQueryLength()).isEqualTo(0);
+ assertThat(sStats.getTermCount()).isEqualTo(2);
+ assertThat(sStats.getQueryLength()).isEqualTo(queryStr.length());
assertThat(sStats.getFilteredNamespaceCount()).isEqualTo(1);
assertThat(sStats.getFilteredSchemaTypeCount()).isEqualTo(1);
- assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(1);
+ assertThat(sStats.getCurrentPageReturnedResultCount()).isEqualTo(2);
assertThat(sStats.isFirstPage()).isTrue();
- assertThat(sStats.getScoredDocumentCount()).isEqualTo(1);
+ assertThat(sStats.getRankingStrategy())
+ .isEqualTo(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP);
+ assertThat(sStats.getScoredDocumentCount()).isEqualTo(2);
+ assertThat(sStats.getResultWithSnippetsCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLoggingStats_search_failure() throws Exception {
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ List<AppSearchSchema> schemas =
+ ImmutableList.of(
+ new AppSearchSchema.Builder("Type1").build(),
+ new AppSearchSchema.Builder("Type2").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ SearchSpec searchSpec =
+ new SearchSpec.Builder()
+ .setTermMatch(TermMatchType.Code.PREFIX_VALUE)
+ .setRankingStrategy(SearchSpec.RANKING_STRATEGY_CREATION_TIMESTAMP)
+ .addFilterPackageNames("anotherPackage")
+ .build();
+
+ mAppSearchImpl.query(
+ testPackageName,
+ testPackageName,
+ /* queryExpression= */ "",
+ searchSpec,
+ /*logger=*/ mLogger);
+
+ SearchStats sStats = mLogger.mSearchStats;
+ assertThat(sStats).isNotNull();
+ assertThat(sStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(sStats.getDatabase()).isEqualTo(testPackageName);
+ assertThat(sStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
}
@Test
- public void testLoggingStats_remove() throws Exception {
+ public void testLoggingStats_remove_success() throws Exception {
// Insert schema
final String testPackageName = "testPackage";
final String testDatabase = "testDatabase";
@@ -391,8 +631,8 @@ public class AppSearchLoggerTest {
testDatabase,
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
GenericDocument document =
@@ -406,12 +646,59 @@ public class AppSearchLoggerTest {
assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
// delete by namespace + id
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE);
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(1);
}
@Test
- public void testLoggingStats_removeByQuery() throws Exception {
+ public void testLoggingStats_remove_failure() throws Exception {
+ // Insert schema
+ final String testPackageName = "testPackage";
+ final String testDatabase = "testDatabase";
+ final String testNamespace = "testNameSpace";
+ final String testId = "id";
+ List<AppSearchSchema> schemas =
+ Collections.singletonList(new AppSearchSchema.Builder("type").build());
+ mAppSearchImpl.setSchema(
+ testPackageName,
+ testDatabase,
+ schemas,
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0);
+
+ GenericDocument document =
+ new GenericDocument.Builder<>(testNamespace, testId, "type").build();
+ mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null);
+
+ RemoveStats.Builder rStatsBuilder = new RemoveStats.Builder(testPackageName, testDatabase);
+
+ // We mainly want to check the status code in stats. So we don't need to inspect the
+ // exception here.
+ Assert.assertThrows(
+ AppSearchException.class,
+ () ->
+ mAppSearchImpl.remove(
+ testPackageName,
+ testDatabase,
+ testNamespace,
+ "invalidId",
+ rStatsBuilder));
+
+ RemoveStats rStats = rStatsBuilder.build();
+ assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
+ assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_NOT_FOUND);
+ // delete by namespace + id
+ assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.SINGLE_VALUE);
+ assertThat(rStats.getDeletedDocumentCount()).isEqualTo(0);
+ }
+
+ @Test
+ public void testLoggingStats_removeByQuery_success() throws Exception {
// Insert schema
final String testPackageName = "testPackage";
final String testDatabase = "testDatabase";
@@ -423,8 +710,8 @@ public class AppSearchLoggerTest {
testDatabase,
schemas,
/*visibilityStore=*/ null,
- /*schemasNotPlatformSurfaceable=*/ Collections.emptyList(),
- /*schemasPackageAccessible=*/ Collections.emptyMap(),
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
/*version=*/ 0);
GenericDocument document1 =
@@ -444,6 +731,7 @@ public class AppSearchLoggerTest {
assertThat(rStats.getPackageName()).isEqualTo(testPackageName);
assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
+ assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
// delete by query
assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.QUERY_VALUE);
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(2);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
index d3feb12912ad..64a670dcdb38 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/converter/SnippetTest.java
@@ -46,7 +46,6 @@ public class SnippetTest {
PREFIX,
Collections.singletonMap(PREFIX + SCHEMA_TYPE, SCHEMA_TYPE_CONFIG_PROTO));
- // TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
public void testSingleStringSnippet() {
final String propertyKeyString = "content";
@@ -112,7 +111,6 @@ public class SnippetTest {
assertThat(match.getSnippet()).isEqualTo(window);
}
- // TODO(tytytyww): Add tests for Double and Long Snippets.
@Test
public void testNoSnippets() {
final String propertyKeyString = "content";
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index 6d9068675a72..57d994155d5b 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -254,14 +254,25 @@ public class AppSearchStatsTest {
@Test
public void testAppSearchStats_SetSchemaStats() {
+ SchemaMigrationStats schemaMigrationStats =
+ new SchemaMigrationStats.Builder()
+ .setGetSchemaLatencyMillis(1)
+ .setQueryAndTransformLatencyMillis(2)
+ .setFirstSetSchemaLatencyMillis(3)
+ .setSecondSetSchemaLatencyMillis(4)
+ .setSaveDocumentLatencyMillis(5)
+ .setMigratedDocumentCount(6)
+ .setSavedDocumentCount(7)
+ .build();
int nativeLatencyMillis = 1;
int newTypeCount = 2;
int compatibleTypeChangeCount = 3;
int indexIncompatibleTypeChangeCount = 4;
int backwardsIncompatibleTypeChangeCount = 5;
- final SetSchemaStats sStats =
+ SetSchemaStats sStats =
new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
.setStatusCode(TEST_STATUS_CODE)
+ .setSchemaMigrationStats(schemaMigrationStats)
.setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
.setNativeLatencyMillis(nativeLatencyMillis)
.setNewTypeCount(newTypeCount)
@@ -274,6 +285,7 @@ public class AppSearchStatsTest {
assertThat(sStats.getPackageName()).isEqualTo(TEST_PACKAGE_NAME);
assertThat(sStats.getDatabase()).isEqualTo(TEST_DATA_BASE);
assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
+ assertThat(sStats.getSchemaMigrationStats()).isEqualTo(schemaMigrationStats);
assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount);
@@ -285,6 +297,35 @@ public class AppSearchStatsTest {
}
@Test
+ public void testAppSearchStats_SchemaMigrationStats() {
+ int getSchemaLatency = 1;
+ int queryAndTransformLatency = 2;
+ int firstSetSchemaLatency = 3;
+ int secondSetSchemaLatency = 4;
+ int saveDocumentLatency = 5;
+ int migratedDocumentCount = 6;
+ int savedDocumentCount = 7;
+ SchemaMigrationStats sStats =
+ new SchemaMigrationStats.Builder()
+ .setGetSchemaLatencyMillis(getSchemaLatency)
+ .setQueryAndTransformLatencyMillis(queryAndTransformLatency)
+ .setFirstSetSchemaLatencyMillis(firstSetSchemaLatency)
+ .setSecondSetSchemaLatencyMillis(secondSetSchemaLatency)
+ .setSaveDocumentLatencyMillis(saveDocumentLatency)
+ .setMigratedDocumentCount(migratedDocumentCount)
+ .setSavedDocumentCount(savedDocumentCount)
+ .build();
+
+ assertThat(sStats.getGetSchemaLatencyMillis()).isEqualTo(getSchemaLatency);
+ assertThat(sStats.getQueryAndTransformLatencyMillis()).isEqualTo(queryAndTransformLatency);
+ assertThat(sStats.getFirstSetSchemaLatencyMillis()).isEqualTo(firstSetSchemaLatency);
+ assertThat(sStats.getSecondSetSchemaLatencyMillis()).isEqualTo(secondSetSchemaLatency);
+ assertThat(sStats.getSaveDocumentLatencyMillis()).isEqualTo(saveDocumentLatency);
+ assertThat(sStats.getMigratedDocumentCount()).isEqualTo(migratedDocumentCount);
+ assertThat(sStats.getSavedDocumentCount()).isEqualTo(savedDocumentCount);
+ }
+
+ @Test
public void testAppSearchStats_RemoveStats() {
int nativeLatencyMillis = 1;
@RemoveStats.DeleteType int deleteType = 2;
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
index 7c275e13e24a..ec96d6a71be4 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/stats/PlatformLoggerTest.java
@@ -65,13 +65,8 @@ public class PlatformLoggerTest {
Context context = ApplicationProvider.getApplicationContext();
mContext = new ContextWrapper(context) {
@Override
- public Context createContextAsUser(UserHandle user, int flags) {
- return new ContextWrapper(super.createContextAsUser(user, flags)) {
- @Override
- public PackageManager getPackageManager() {
- return getMockPackageManager(user);
- }
- };
+ public PackageManager getPackageManager() {
+ return getMockPackageManager(mContext.getUser());
}
};
}
@@ -153,7 +148,6 @@ public class PlatformLoggerTest {
final int testUid = 1234;
PlatformLogger logger = new PlatformLogger(
mContext,
- mContext.getUser(),
AppSearchConfig.create(DIRECT_EXECUTOR));
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
when(mockPackageManager.getPackageUid(testPackageName, /*flags=*/0)).thenReturn(testUid);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java b/services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java
index b67ebe423eab..07a728bac2a5 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/VisibilityStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/visibilitystore/VisibilityStoreImplTest.java
@@ -14,10 +14,7 @@
* limitations under the License.
*/
-// TODO(b/169883602): This is purposely a different package from the path so that it can access
-// AppSearchImpl methods without having to make methods public. This should be moved into a proper
-// package once AppSearchImpl-VisibilityStore's dependencies are refactored.
-package com.android.server.appsearch.external.localstorage;
+package com.android.server.appsearch.visibilitystore;
import static android.Manifest.permission.READ_GLOBAL_APP_SEARCH_DATA;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
@@ -39,8 +36,10 @@ import android.util.ArrayMap;
import androidx.test.core.app.ApplicationProvider;
+import com.android.server.appsearch.external.localstorage.AppSearchImpl;
+import com.android.server.appsearch.external.localstorage.OptimizeStrategy;
import com.android.server.appsearch.external.localstorage.util.PrefixUtil;
-import com.android.server.appsearch.visibilitystore.VisibilityStore;
+import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -55,7 +54,7 @@ import org.mockito.Mockito;
import java.util.Collections;
import java.util.Map;
-public class VisibilityStoreTest {
+public class VisibilityStoreImplTest {
/**
* Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
*/
@@ -64,7 +63,7 @@ public class VisibilityStoreTest {
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private final Map<UserHandle, PackageManager> mMockPackageManagers = new ArrayMap<>();
private Context mContext;
- private VisibilityStore mVisibilityStore;
+ private VisibilityStoreImpl mVisibilityStore;
private int mUid;
@Before
@@ -90,7 +89,7 @@ public class VisibilityStoreTest {
// Give ourselves global query permissions
AppSearchImpl appSearchImpl = AppSearchImpl.create(
mTemporaryFolder.newFolder(), /*initStatsBuilder=*/ null, ALWAYS_OPTIMIZE);
- mVisibilityStore = VisibilityStore.create(appSearchImpl, mContext);
+ mVisibilityStore = VisibilityStoreImpl.create(appSearchImpl, mContext);
mUid = mContext.getPackageManager().getPackageUid(mContext.getPackageName(), /*flags=*/ 0);
}
@@ -132,7 +131,7 @@ public class VisibilityStoreTest {
}
@Test
- public void testSetVisibility_platformSurfaceable() throws Exception {
+ public void testSetVisibility_displayedBySystem() throws Exception {
// Make sure we have global query privileges
PackageManager mockPackageManager = getMockPackageManager(mContext.getUser());
when(mockPackageManager
@@ -143,9 +142,9 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
+ /*schemasNotDisplayedBySystem=*/ ImmutableSet.of(
"prefix/schema1", "prefix/schema2"),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
+ /*schemasVisibleToPackages=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -168,9 +167,9 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ ImmutableSet.of(
+ /*schemasNotDisplayedBySystem=*/ ImmutableSet.of(
"prefix/schema1", "prefix/schema3"),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
+ /*schemasVisibleToPackages=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -200,8 +199,8 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ Collections.emptyMap());
+ /*schemasNotDisplayedBySystem=*/ Collections.emptySet(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap());
assertThat(
mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -229,7 +228,7 @@ public class VisibilityStoreTest {
}
@Test
- public void testSetVisibility_packageAccessible() throws Exception {
+ public void testSetVisibility_visibleToPackages() throws Exception {
// Values for a "foo" client
String packageNameFoo = "packageFoo";
byte[] sha256CertFoo = new byte[] {10};
@@ -272,8 +271,8 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.emptySet(),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"prefix/schemaFoo",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo)),
"prefix/schemaBar",
@@ -339,8 +338,8 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.emptySet(),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"prefix/schemaFoo",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
@@ -392,8 +391,8 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
"package",
"database",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.emptySet(),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"prefix/schemaFoo",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
@@ -425,8 +424,8 @@ public class VisibilityStoreTest {
mVisibilityStore.setVisibility(
/*packageName=*/ "",
/*databaseName=*/ "",
- /*schemasNotPlatformSurfaceable=*/ Collections.emptySet(),
- /*schemasPackageAccessible=*/ ImmutableMap.of(
+ /*schemasNotDisplayedBySystem=*/ Collections.emptySet(),
+ /*schemasVisibleToPackages=*/ ImmutableMap.of(
"schema",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))));
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index c0df2e33ffed..cae6c863ab02 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -48,8 +48,11 @@ import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.display.BrightnessInfo;
import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Handler;
@@ -120,7 +123,7 @@ public class DisplayModeDirectorTest {
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
when(mContext.getContentResolver()).thenReturn(resolver);
- mInjector = new FakesInjector();
+ mInjector = spy(new FakesInjector());
mHandler = new Handler(Looper.getMainLooper());
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1256,13 +1259,163 @@ public class DisplayModeDirectorTest {
assertNull(vote);
}
+ @Test
+ public void testHbmVoting_forHdr() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Limitation
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
+ List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ 60.f, 60.f)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, 60.f);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+ }
+
+ @Test
+ public void testHbmVoting_forSunlight() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Limitation
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
+ List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ 60.f, 60.f)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, 60.f);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+ }
+
+ @Test
+ public void testHbmVoting_forSunlight_NoLimitation() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Limitation for different display
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID + 1)).thenReturn(
+ List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ 60.f, 60.f)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+ }
+
+ @Test
+ public void testHbmVoting_RemovedDisplay() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor =
+ ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Limitation for different display
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
+ List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
+ 60.f, 60.f)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn on HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, 60.f);
+
+ // Turn off HBM
+ listener.onDisplayRemoved(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+ }
+
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
}
- private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
+ public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
@Override
public String getProperty(String namespace, String name) {
Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
@@ -1403,7 +1556,7 @@ public class DisplayModeDirectorTest {
mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
}
- static class FakesInjector implements DisplayModeDirector.Injector {
+ public static class FakesInjector implements DisplayModeDirector.Injector {
private final FakeDeviceConfig mDeviceConfig;
private ContentObserver mBrightnessObserver;
private ContentObserver mPeakRefreshRateObserver;
@@ -1444,6 +1597,14 @@ public class DisplayModeDirectorTest {
mPeakRefreshRateObserver = observer;
}
+ @Override
+ public void registerDisplayListener(DisplayListener listener, Handler handler, long flag) {}
+
+ @Override
+ public BrightnessInfo getBrightnessInfo(int displayId) {
+ return null;
+ }
+
void notifyPeakRefreshRateChanged() {
if (mPeakRefreshRateObserver != null) {
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 7df2dd6988bf..c572dd65245f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -649,7 +649,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
protected class MockAppSearchManager implements IAppSearchManager {
- protected Map<String, List<PackageIdentifier>> mSchemasPackageAccessible =
+ protected Map<String, List<PackageIdentifier>> mSchemasVisibleToPackages =
new ArrayMap<>(1);
private Map<String, Map<String, GenericDocument>> mDocumentMap = new ArrayMap<>(1);
@@ -659,19 +659,19 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
@Override
public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles,
- List<String> schemasNotPlatformSurfaceable,
- Map<String, List<Bundle>> schemasPackageAccessibleBundles, boolean forceOverride,
+ List<String> schemasNotDisplayedBySystem,
+ Map<String, List<Bundle>> schemasVisibleToPackagesBundles, boolean forceOverride,
int version, UserHandle userHandle, long binderCallStartTimeMillis,
IAppSearchResultCallback callback) throws RemoteException {
for (Map.Entry<String, List<Bundle>> entry :
- schemasPackageAccessibleBundles.entrySet()) {
+ schemasVisibleToPackagesBundles.entrySet()) {
final String key = entry.getKey();
final List<PackageIdentifier> packageIdentifiers;
- if (!mSchemasPackageAccessible.containsKey(key)) {
+ if (!mSchemasVisibleToPackages.containsKey(key)) {
packageIdentifiers = new ArrayList<>(entry.getValue().size());
- mSchemasPackageAccessible.put(key, packageIdentifiers);
+ mSchemasVisibleToPackages.put(key, packageIdentifiers);
} else {
- packageIdentifiers = mSchemasPackageAccessible.get(key);
+ packageIdentifiers = mSchemasVisibleToPackages.get(key);
}
for (int i = 0; i < entry.getValue().size(); i++) {
packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i)));
@@ -785,7 +785,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
@Override
- public void getNextPage(long nextPageToken, UserHandle userHandle,
+ public void getNextPage(String packageName, long nextPageToken, UserHandle userHandle,
IAppSearchResultCallback callback) throws RemoteException {
final Bundle page = new Bundle();
page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
@@ -795,8 +795,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
@Override
- public void invalidateNextPageToken(long nextPageToken, UserHandle userHandle)
- throws RemoteException {
+ public void invalidateNextPageToken(String packageName, long nextPageToken,
+ UserHandle userHandle) throws RemoteException {
}
@Override
@@ -875,13 +875,13 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
}
@Override
- public void persistToDisk(UserHandle userHandle, long binderCallStartTimeMillis)
- throws RemoteException {
+ public void persistToDisk(String packageName, UserHandle userHandle,
+ long binderCallStartTimeMillis) throws RemoteException {
}
@Override
- public void initialize(UserHandle userHandle, long binderCallStartTimeMillis,
- IAppSearchResultCallback callback)
+ public void initialize(String packageName, UserHandle userHandle,
+ long binderCallStartTimeMillis, IAppSearchResultCallback callback)
throws RemoteException {
ignore(callback);
}
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 17d99e652726..9044b27d4994 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -222,6 +222,64 @@ public class SystemConfigTest {
}
/**
+ * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-vendor-apex}.
+ */
+ @Test
+ public void readPermissions_allowVendorApex_parsesVendorApexAllowList()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getAllowedVendorApexes()).containsExactly("com.android.apex1");
+ }
+
+ /**
+ * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-vendor-apex}.
+ */
+ @Test
+ public void readPermissions_allowVendorApex_parsesVendorApexAllowList_noPackage()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <allowed-vendor-apex/>\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0);
+
+ assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
+ }
+
+
+ /**
+ * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_VENDOR_APEX}
+ * permission flag for the tag: {@code allowed-oem-apex}.
+ */
+ @Test
+ public void readPermissions_notAllowVendorApex_doesNotParseVendorApexAllowList()
+ throws IOException {
+ final String contents =
+ "<config>\n"
+ + " <allowed-vendor-apex package=\"com.android.apex1\" />\n"
+ + "</config>";
+ final File folder = createTempSubfolder("folder");
+ createTempFile(folder, "vendor-apex-allowlist.xml", contents);
+
+ mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400);
+
+ assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty();
+ }
+
+ /**
* Creates folderName/fileName in the mTemporaryFolder and fills it with the contents.
*
* @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
index 058575817acf..0449e4450d06 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/FakeVibratorControllerProvider.java
@@ -56,6 +56,8 @@ final class FakeVibratorControllerProvider {
private int[] mSupportedEffects;
private int[] mSupportedBraking;
private int[] mSupportedPrimitives;
+ private int mCompositionSizeMax;
+ private int mPwleSizeMax;
private float mMinFrequency = Float.NaN;
private float mResonantFrequency = Float.NaN;
private float mFrequencyResolution = Float.NaN;
@@ -151,12 +153,22 @@ final class FakeVibratorControllerProvider {
}
@Override
- public VibratorInfo getInfo(float suggestedFrequencyRange) {
- VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping(
- mMinFrequency, mResonantFrequency, mFrequencyResolution,
- suggestedFrequencyRange, mMaxAmplitudes);
- return new VibratorInfo(vibratorId, mCapabilities, mSupportedEffects, mSupportedBraking,
- mSupportedPrimitives, null, mQFactor, frequencyMapping);
+ public boolean getInfo(float suggestedFrequencyRange, VibratorInfo.Builder infoBuilder) {
+ infoBuilder.setCapabilities(mCapabilities);
+ infoBuilder.setSupportedBraking(mSupportedBraking);
+ infoBuilder.setPwleSizeMax(mPwleSizeMax);
+ infoBuilder.setSupportedEffects(mSupportedEffects);
+ if (mSupportedPrimitives != null) {
+ for (int primitive : mSupportedPrimitives) {
+ infoBuilder.setSupportedPrimitive(primitive, EFFECT_DURATION);
+ }
+ }
+ infoBuilder.setCompositionSizeMax(mCompositionSizeMax);
+ infoBuilder.setQFactor(mQFactor);
+ infoBuilder.setFrequencyMapping(new VibratorInfo.FrequencyMapping(mMinFrequency,
+ mResonantFrequency, mFrequencyResolution, suggestedFrequencyRange,
+ mMaxAmplitudes));
+ return true;
}
private void applyLatency() {
@@ -236,6 +248,16 @@ final class FakeVibratorControllerProvider {
mSupportedPrimitives = primitives;
}
+ /** Set the max number of primitives allowed in a composition by the fake vibrator hardware. */
+ public void setCompositionSizeMax(int compositionSizeMax) {
+ mCompositionSizeMax = compositionSizeMax;
+ }
+
+ /** Set the max number of PWLEs allowed in a composition by the fake vibrator hardware. */
+ public void setPwleSizeMax(int pwleSizeMax) {
+ mPwleSizeMax = pwleSizeMax;
+ }
+
/** Set the resonant frequency of the fake vibrator hardware. */
public void setResonantFrequency(float frequencyHz) {
mResonantFrequency = frequencyHz;
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
index f4eb2ded5a9d..32988efbab2c 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/StepToRampAdapterTest.java
@@ -68,6 +68,38 @@ public class StepToRampAdapterTest {
}
@Test
+ public void testRampSegments_withPwleDurationLimit_splitsLongRamps() {
+ List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ -1, /* duration= */ 25),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5)));
+ List<VibrationEffectSegment> expectedSegments = Arrays.asList(
+ new RampSegment(/* startAmplitude= */ 0.5f, /* endAmplitude*/ 0.5f,
+ /* startFrequency= */ -1, /* endFrequency= */ -1, /* duration= */ 10),
+ new RampSegment(/* startAmplitude= */ 0, /* endAmplitude= */ 0.32f,
+ /* startFrequency= */ 0, /* endFrequency= */ -0.32f, /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.32f, /* endAmplitude= */ 0.64f,
+ /* startFrequency= */ -0.32f, /* endFrequency= */ -0.64f,
+ /* duration= */ 8),
+ new RampSegment(/* startAmplitude= */ 0.64f, /* endAmplitude= */ 1,
+ /* startFrequency= */ -0.64f, /* endFrequency= */ -1, /* duration= */ 9),
+ new RampSegment(/* startAmplitude= */ 1, /* endAmplitude*/ 1,
+ /* startFrequency= */ 0, /* endFrequency= */ 1, /* duration= */ 5));
+
+ VibratorInfo vibratorInfo = new VibratorInfo.Builder(0)
+ .setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)
+ .setPwlePrimitiveDurationMax(10)
+ .build();
+
+ // Update repeat index to skip the ramp splits.
+ assertEquals(4, mAdapter.apply(segments, 2, vibratorInfo));
+ assertEquals(expectedSegments, segments);
+ }
+
+ @Test
public void testStepAndRampSegments_withoutPwleCapability_keepsListUnchanged() {
mAdapter = new StepToRampAdapter(50);
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index f02e2f081e3b..b8fdb552e453 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -356,7 +356,8 @@ public class VibrationThreadTest {
@Test
public void vibrate_singleVibratorComposed_runsVibration() throws Exception {
- mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
long vibrationId = 1;
VibrationEffect effect = VibrationEffect.startComposition()
@@ -374,7 +375,7 @@ public class VibrationThreadTest {
assertEquals(Arrays.asList(
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 0),
expectedPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f, 0)),
- mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
+ fakeVibrator.getEffectSegments());
}
@Test
@@ -395,6 +396,27 @@ public class VibrationThreadTest {
}
@Test
+ public void vibrate_singleVibratorLargeComposition_splitsVibratorComposeCalls() {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+ fakeVibrator.setCompositionSizeMax(2);
+
+ long vibrationId = 1;
+ VibrationEffect effect = VibrationEffect.startComposition()
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
+ .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SPIN, 0.8f)
+ .compose();
+ VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+ waitForCompletion(thread);
+
+ verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+ // Vibrator compose called twice.
+ verify(mControllerCallbacks, times(2)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+ assertEquals(3, fakeVibrator.getEffectSegments().size());
+ }
+
+ @Test
public void vibrate_singleVibratorComposedEffects_runsDifferentVibrations() throws Exception {
mVibratorProviders.get(VIBRATOR_ID).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
mVibratorProviders.get(VIBRATOR_ID).setSupportedPrimitives(
@@ -432,12 +454,13 @@ public class VibrationThreadTest {
@Test
public void vibrate_singleVibratorPwle_runsComposePwle() throws Exception {
- mVibratorProviders.get(VIBRATOR_ID).setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
- mVibratorProviders.get(VIBRATOR_ID).setSupportedBraking(Braking.CLAB);
- mVibratorProviders.get(VIBRATOR_ID).setMinFrequency(100);
- mVibratorProviders.get(VIBRATOR_ID).setResonantFrequency(150);
- mVibratorProviders.get(VIBRATOR_ID).setFrequencyResolution(50);
- mVibratorProviders.get(VIBRATOR_ID).setMaxAmplitudes(
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ fakeVibrator.setSupportedBraking(Braking.CLAB);
+ fakeVibrator.setMinFrequency(100);
+ fakeVibrator.setResonantFrequency(150);
+ fakeVibrator.setFrequencyResolution(50);
+ fakeVibrator.setMaxAmplitudes(
0.5f /* 100Hz*/, 1 /* 150Hz */, 0.6f /* 200Hz */);
long vibrationId = 1;
@@ -462,8 +485,34 @@ public class VibrationThreadTest {
expectedRamp(/* amplitude= */ 0.6f, /* frequency= */ 200, /* duration= */ 30),
expectedRamp(/* StartAmplitude= */ 0.6f, /* endAmplitude= */ 0.5f,
/* startFrequency= */ 200, /* endFrequency= */ 100, /* duration= */ 40)),
- mVibratorProviders.get(VIBRATOR_ID).getEffectSegments());
- assertEquals(Arrays.asList(Braking.CLAB), mVibratorProviders.get(VIBRATOR_ID).getBraking());
+ fakeVibrator.getEffectSegments());
+ assertEquals(Arrays.asList(Braking.CLAB), fakeVibrator.getBraking());
+ }
+
+ @Test
+ public void vibrate_singleVibratorLargePwle_splitsVibratorComposeCalls() {
+ FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(VIBRATOR_ID);
+ fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_PWLE_EFFECTS);
+ fakeVibrator.setMinFrequency(100);
+ fakeVibrator.setResonantFrequency(150);
+ fakeVibrator.setFrequencyResolution(50);
+ fakeVibrator.setMaxAmplitudes(1, 1, 1);
+ fakeVibrator.setPwleSizeMax(2);
+
+ long vibrationId = 1;
+ VibrationEffect effect = VibrationEffect.startWaveform()
+ .addStep(1, 10)
+ .addRamp(0, 20)
+ .addStep(0.8f, 1, 30)
+ .addRamp(0.6f, -1, 40)
+ .build();
+ VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
+ waitForCompletion(thread);
+
+ verify(mThreadCallbacks).onVibrationEnded(eq(vibrationId), eq(Vibration.Status.FINISHED));
+ // Vibrator compose called twice.
+ verify(mControllerCallbacks, times(2)).onComplete(eq(VIBRATOR_ID), eq(vibrationId));
+ assertEquals(4, fakeVibrator.getEffectSegments().size());
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
index 9e98e7d0410c..a732bd18676a 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibratorControllerTest.java
@@ -298,11 +298,13 @@ public class VibratorControllerTest {
private void mockVibratorCapabilities(int capabilities) {
VibratorInfo.FrequencyMapping frequencyMapping = new VibratorInfo.FrequencyMapping(
Float.NaN, Float.NaN, Float.NaN, Float.NaN, null);
- when(mNativeWrapperMock.getInfo(anyFloat())).thenReturn(
- new VibratorInfo.Builder(VIBRATOR_ID)
- .setCapabilities(capabilities)
- .setFrequencyMapping(frequencyMapping)
- .build());
+ when(mNativeWrapperMock.getInfo(anyFloat(), any(VibratorInfo.Builder.class)))
+ .then(invocation -> {
+ ((VibratorInfo.Builder) invocation.getArgument(1))
+ .setCapabilities(capabilities)
+ .setFrequencyMapping(frequencyMapping);
+ return true;
+ });
}
private PrebakedSegment createPrebaked(int effectId, int effectStrength) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 3862d754b8f5..71c05b5c46f7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -48,6 +48,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
@@ -111,6 +112,8 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
NotificationUsageStats mUsageStats;
@Mock
IAccessibilityManager mAccessibilityService;
+ @Mock
+ KeyguardManager mKeyguardManager;
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@@ -153,6 +156,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mUsageStats.isAlertRateLimited(any())).thenReturn(false);
when(mVibrator.hasFrequencyControl()).thenReturn(false);
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
long serviceReturnValue = IntPair.of(
AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED,
@@ -174,6 +178,7 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
mService.setScreenOn(false);
mService.setUsageStats(mUsageStats);
mService.setAccessibilityManager(accessibilityManager);
+ mService.setKeyguardManager(mKeyguardManager);
mService.mScreenOn = false;
mService.mInCallStateOffHook = false;
mService.mNotificationPulseEnabled = true;
@@ -496,6 +501,94 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
}
@Test
+ public void testLockedPrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedOverridePrivateA11yRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(Notification.VISIBILITY_PRIVATE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification().publicVersion, event.getParcelableData());
+ }
+
+ @Test
+ public void testLockedPublicA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PUBLIC;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(true);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
+ public void testUnlockedPrivateA11yNoRedaction() throws Exception {
+ NotificationRecord r = getBeepyNotification();
+ r.setPackageVisibilityOverride(NotificationManager.VISIBILITY_NO_OVERRIDE);
+ r.getNotification().visibility = Notification.VISIBILITY_PRIVATE;
+ when(mKeyguardManager.isDeviceLocked(anyInt())).thenReturn(false);
+ AccessibilityManager accessibilityManager = Mockito.mock(AccessibilityManager.class);
+ when(accessibilityManager.isEnabled()).thenReturn(true);
+ mService.setAccessibilityManager(accessibilityManager);
+
+ mService.buzzBeepBlinkLocked(r);
+
+ ArgumentCaptor<AccessibilityEvent> eventCaptor =
+ ArgumentCaptor.forClass(AccessibilityEvent.class);
+
+ verify(accessibilityManager, times(1))
+ .sendAccessibilityEvent(eventCaptor.capture());
+
+ AccessibilityEvent event = eventCaptor.getValue();
+ assertEquals(r.getNotification(), event.getParcelableData());
+ }
+
+ @Test
public void testBeepInsistently() throws Exception {
NotificationRecord r = getInsistentBeepyNotification();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index a522b5c6161e..1f543a17885a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -94,6 +94,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
@@ -2425,6 +2426,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
eq(mTestNotificationChannel.getId()), anyBoolean()))
.thenReturn(mTestNotificationChannel);
+ when(mPreferencesHelper.deleteNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()))).thenReturn(true);
reset(mListeners);
mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
@@ -2433,6 +2436,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception {
+ List<String> associations = new ArrayList<>();
+ associations.add("a");
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(associations);
+ mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(null);
+ reset(mListeners);
+ mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
+ verifyNoMoreInteractions(mListeners);
+ verifyNoMoreInteractions(mHistoryManager);
+ }
+
+ @Test
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 3a51ff2fb5fa..23da02c0e4a1 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -3333,6 +3333,17 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
+ public void testDeleted_twice() throws Exception {
+ mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
+ mAppOpsManager, mStatsEventBuilderFactory);
+
+ mHelper.createNotificationChannel(
+ PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+ assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
+ assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
+ }
+
+ @Test
public void testDeleted_recentTime() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
mAppOpsManager, mStatsEventBuilderFactory);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 9267285b446b..9cf29d4dcc50 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -53,6 +54,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -1012,12 +1014,26 @@ public class RootWindowContainerTests extends WindowTestsBase {
// Create another activity on top and the user id is 1
final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task)
.setUid(UserHandle.PER_USER_RANGE + 1).build();
+ doReturn(true).when(topActivity).okToShowLocked();
+ topActivity.intent.setAction(Intent.ACTION_MAIN);
// Make sure the listeners will be notified for putting the task to locked state
TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
spyOn(controller);
mWm.mRoot.lockAllProfileTasks(0);
verify(controller).notifyTaskProfileLocked(eq(taskId), eq(0));
+
+ // Create the work lock activity on top of the task
+ final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task)
+ .setUid(UserHandle.PER_USER_RANGE + 1).build();
+ doReturn(true).when(workLockActivity).okToShowLocked();
+ workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
+ doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked();
+
+ // Make sure the listener won't be notified again.
+ clearInvocations(controller);
+ mWm.mRoot.lockAllProfileTasks(0);
+ verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt());
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 4e261deb67f6..4872ec511ccc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -401,6 +401,7 @@ public class SizeCompatTests extends WindowTestsBase {
assertFitted();
final Rect currentBounds = mActivity.getWindowConfiguration().getBounds();
+ final Rect currentAppBounds = mActivity.getWindowConfiguration().getAppBounds();
final Rect originalBounds = new Rect(mActivity.getWindowConfiguration().getBounds());
final int notchHeight = 100;
@@ -428,8 +429,8 @@ public class SizeCompatTests extends WindowTestsBase {
// Because the display cannot rotate, the portrait activity will fit the short side of
// display with keeping portrait bounds [200, 0 - 700, 1000] in center.
assertEquals(newDisplayBounds.height(), currentBounds.height());
- assertEquals(currentBounds.height() * newDisplayBounds.height() / newDisplayBounds.width(),
- currentBounds.width());
+ assertEquals(currentAppBounds.height() * newDisplayBounds.height()
+ / newDisplayBounds.width(), currentAppBounds.width());
assertFitted();
// The appBounds should be [200, 100 - 700, 1000].
final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index d93ebb383b3b..0ebff1d253ef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -60,6 +60,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
@@ -121,8 +122,8 @@ public class TaskTests extends WindowTestsBase {
@Test
public void testRemoveContainer() {
- final Task taskController1 = createTask(mDisplayContent);
- final Task task = createTaskInRootTask(taskController1, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
task.removeIfPossible();
@@ -130,12 +131,14 @@ public class TaskTests extends WindowTestsBase {
assertNull(task.getParent());
assertEquals(0, task.getChildCount());
assertNull(activity.getParent());
+ verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task);
+ verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask);
}
@Test
public void testRemoveContainer_deferRemoval() {
- final Task taskController1 = createTask(mDisplayContent);
- final Task task = createTaskInRootTask(taskController1, 0 /* userId */);
+ final Task rootTask = createTask(mDisplayContent);
+ final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
doReturn(true).when(task).shouldDeferRemoval();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 128602d5acbd..1b8492722c10 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2226,7 +2226,14 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public long getLastTimeAnyComponentUsed(String packageName) {
+ public long getLastTimeAnyComponentUsed(String packageName, String callingPackage) {
+ if (!hasPermissions(
+ callingPackage, android.Manifest.permission.INTERACT_ACROSS_USERS)) {
+ throw new SecurityException("Caller doesn't have INTERACT_ACROSS_USERS permission");
+ }
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException("Don't have permission to query usage stats");
+ }
synchronized (mLock) {
// Truncate the returned milliseconds to the boundary of the last day before exact
// time for privacy reasons.
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index eac21b492f10..5183e5b8e246 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -863,7 +863,12 @@ public class SoundTriggerService extends SystemService {
}
private void enforceCallingPermission(String permission) {
- PermissionUtil.checkPermissionForPreflight(mContext, mOriginatorIdentity, permission);
+ if (PermissionUtil.checkPermissionForPreflight(mContext, mOriginatorIdentity,
+ permission) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Identity " + mOriginatorIdentity + " does not have permission "
+ + permission);
+ }
}
private void enforceDetectionPermissions(ComponentName detectionService) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 17303a4aa7e1..beaca68b9a37 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -29,11 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.SoundTrigger;
-import android.media.AudioAttributes;
import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.MediaRecorder;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -66,12 +62,16 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.time.Duration;
+import java.time.Instant;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
/**
* A class that provides the communication with the HotwordDetectionService.
@@ -81,33 +81,38 @@ final class HotwordDetectionConnection {
// TODO (b/177502877): Set the Debug flag to false before shipping.
private static final boolean DEBUG = true;
- // Number of bytes per sample of audio (which is a short).
- private static final int BYTES_PER_SAMPLE = 2;
// TODO: These constants need to be refined.
private static final long VALIDATION_TIMEOUT_MILLIS = 3000;
- private static final long VOICE_INTERACTION_TIMEOUT_TO_OPEN_MIC_MILLIS = 2000;
- private static final int MAX_STREAMING_SECONDS = 10;
- private static final int MICROPHONE_BUFFER_LENGTH_SECONDS = 8;
- private static final int HOTWORD_AUDIO_LENGTH_SECONDS = 3;
private static final long MAX_UPDATE_TIMEOUT_MILLIS = 6000;
+ private static final Duration MAX_UPDATE_TIMEOUT_DURATION =
+ Duration.ofMillis(MAX_UPDATE_TIMEOUT_MILLIS);
private final Executor mAudioCopyExecutor = Executors.newCachedThreadPool();
// TODO: This may need to be a Handler(looper)
private final ScheduledExecutorService mScheduledExecutorService =
Executors.newSingleThreadScheduledExecutor();
- private final AtomicBoolean mUpdateStateFinish = new AtomicBoolean(false);
+ private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
+ private final @NonNull ServiceConnectionFactory mServiceConnectionFactory;
final Object mLock;
final int mVoiceInteractionServiceUid;
final ComponentName mDetectionComponentName;
final int mUser;
final Context mContext;
- final @NonNull ServiceConnector<IHotwordDetectionService> mRemoteHotwordDetectionService;
- boolean mBound;
volatile HotwordDetectionServiceIdentity mIdentity;
+ private IHotwordRecognitionStatusCallback mCallback;
+ private IMicrophoneHotwordDetectionVoiceInteractionCallback mSoftwareCallback;
+ private Instant mLastRestartInstant;
+
+ private ScheduledFuture<?> mCancellationTaskFuture;
@GuardedBy("mLock")
private ParcelFileDescriptor mCurrentAudioSink;
+ @GuardedBy("mLock")
+ private boolean mValidatingDspTrigger = false;
+ @GuardedBy("mLock")
+ private boolean mPerformingSoftwareHotwordDetection;
+ private @NonNull ServiceConnection mRemoteHotwordDetectionService;
HotwordDetectionConnection(Object lock, Context context, int voiceInteractionServiceUid,
ComponentName serviceName, int userId, boolean bindInstantServiceAllowed,
@@ -121,50 +126,36 @@ final class HotwordDetectionConnection {
final Intent intent = new Intent(HotwordDetectionService.SERVICE_INTERFACE);
intent.setComponent(mDetectionComponentName);
- mRemoteHotwordDetectionService = new ServiceConnector.Impl<IHotwordDetectionService>(
- mContext, intent, bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, mUser,
- IHotwordDetectionService.Stub::asInterface) {
- @Override // from ServiceConnector.Impl
- protected void onServiceConnectionStatusChanged(IHotwordDetectionService service,
- boolean connected) {
- if (DEBUG) {
- Slog.d(TAG, "onServiceConnectionStatusChanged connected = " + connected);
- }
- synchronized (mLock) {
- mBound = connected;
- }
- }
+ mServiceConnectionFactory = new ServiceConnectionFactory(intent, bindInstantServiceAllowed);
- @Override
- protected long getAutoDisconnectTimeoutMs() {
- return -1;
- }
+ mRemoteHotwordDetectionService = mServiceConnectionFactory.create();
- @Override
- public void binderDied() {
- super.binderDied();
- Slog.w(TAG, "binderDied");
- try {
- callback.onError(-1);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to report onError status: " + e);
- }
- }
- };
- mRemoteHotwordDetectionService.connect();
if (callback == null) {
updateStateLocked(options, sharedMemory);
return;
}
- updateAudioFlinger();
- updateContentCaptureManager();
- updateStateWithCallbackLocked(options, sharedMemory, callback);
+ mCallback = callback;
+
+ mLastRestartInstant = Instant.now();
+ updateStateAfterProcessStart(options, sharedMemory);
+
+ // TODO(volnov): we need to be smarter here, e.g. schedule it a bit more often, but wait
+ // until the current session is closed.
+ mCancellationTaskFuture = mScheduledExecutorService.scheduleAtFixedRate(() -> {
+ if (DEBUG) {
+ Slog.i(TAG, "Time to restart the process, TTL has passed");
+ }
+
+ synchronized (mLock) {
+ restartProcessLocked();
+ }
+ }, 30, 30, TimeUnit.MINUTES);
}
- private void updateStateWithCallbackLocked(PersistableBundle options,
- SharedMemory sharedMemory, IHotwordRecognitionStatusCallback callback) {
+ private void updateStateAfterProcessStart(
+ PersistableBundle options, SharedMemory sharedMemory) {
if (DEBUG) {
- Slog.d(TAG, "updateStateWithCallbackLocked");
+ Slog.d(TAG, "updateStateAfterProcessStart");
}
mRemoteHotwordDetectionService.postAsync(service -> {
AndroidFuture<Void> future = new AndroidFuture<>();
@@ -183,21 +174,21 @@ final class HotwordDetectionConnection {
mIdentity =
new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
future.complete(null);
+ if (mUpdateStateAfterStartFinished.getAndSet(true)) {
+ Slog.w(TAG, "call callback after timeout");
+ return;
+ }
+ int status = bundle != null ? bundle.getInt(
+ KEY_INITIALIZATION_STATUS,
+ INITIALIZATION_STATUS_UNKNOWN)
+ : INITIALIZATION_STATUS_UNKNOWN;
+ // Add the protection to avoid unexpected status
+ if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
+ && status != INITIALIZATION_STATUS_UNKNOWN) {
+ status = INITIALIZATION_STATUS_UNKNOWN;
+ }
try {
- if (mUpdateStateFinish.getAndSet(true)) {
- Slog.w(TAG, "call callback after timeout");
- return;
- }
- int status = bundle != null ? bundle.getInt(
- KEY_INITIALIZATION_STATUS,
- INITIALIZATION_STATUS_UNKNOWN)
- : INITIALIZATION_STATUS_UNKNOWN;
- // Add the protection to avoid unexpected status
- if (status > HotwordDetectionService.getMaxCustomInitializationStatus()
- && status != INITIALIZATION_STATUS_UNKNOWN) {
- status = INITIALIZATION_STATUS_UNKNOWN;
- }
- callback.onStatusReported(status);
+ mCallback.onStatusReported(status);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to report initialization status: " + e);
}
@@ -214,13 +205,13 @@ final class HotwordDetectionConnection {
.whenComplete((res, err) -> {
if (err instanceof TimeoutException) {
Slog.w(TAG, "updateState timed out");
+ if (mUpdateStateAfterStartFinished.getAndSet(true)) {
+ return;
+ }
try {
- if (mUpdateStateFinish.getAndSet(true)) {
- return;
- }
- callback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
+ mCallback.onStatusReported(INITIALIZATION_STATUS_UNKNOWN);
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to report initialization status: " + e);
+ Slog.w(TAG, "Failed to report initialization status UNKNOWN", e);
}
} else if (err != null) {
Slog.w(TAG, "Failed to update state: " + err);
@@ -230,27 +221,9 @@ final class HotwordDetectionConnection {
});
}
- private void updateAudioFlinger() {
- // TODO: Consider using a proxy that limits the exposed API surface.
- IBinder audioFlinger = ServiceManager.getService("media.audio_flinger");
- if (audioFlinger == null) {
- throw new IllegalStateException("Service media.audio_flinger wasn't found.");
- }
- mRemoteHotwordDetectionService.post(service -> service.updateAudioFlinger(audioFlinger));
- }
-
- private void updateContentCaptureManager() {
- IBinder b = ServiceManager
- .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
- IContentCaptureManager binderService = IContentCaptureManager.Stub.asInterface(b);
- mRemoteHotwordDetectionService.post(
- service -> service.updateContentCaptureManager(binderService,
- new ContentCaptureOptions(null)));
- }
-
private boolean isBound() {
synchronized (mLock) {
- return mBound;
+ return mRemoteHotwordDetectionService.isBound();
}
}
@@ -258,18 +231,25 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "cancelLocked");
}
- if (mBound) {
+ if (mRemoteHotwordDetectionService.isBound()) {
mRemoteHotwordDetectionService.unbind();
- mBound = false;
LocalServices.getService(PermissionManagerServiceInternal.class)
.setHotwordDetectionServiceProvider(null);
mIdentity = null;
}
+ mCancellationTaskFuture.cancel(/* may interrupt */ true);
}
void updateStateLocked(PersistableBundle options, SharedMemory sharedMemory) {
- mRemoteHotwordDetectionService.run(
- service -> service.updateState(options, sharedMemory, null /* callback */));
+ // Prevent doing the init late, so restart is handled equally to a clean process start.
+ // TODO(b/191742511): this logic needs a test
+ if (!mUpdateStateAfterStartFinished.get()
+ && Instant.now().minus(MAX_UPDATE_TIMEOUT_DURATION).isBefore(mLastRestartInstant)) {
+ updateStateAfterProcessStart(options, sharedMemory);
+ } else {
+ mRemoteHotwordDetectionService.run(
+ service -> service.updateState(options, sharedMemory, null /* callback */));
+ }
}
void startListeningFromMic(
@@ -278,7 +258,20 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "startListeningFromMic");
}
+ mSoftwareCallback = callback;
+
+ synchronized (mLock) {
+ if (mPerformingSoftwareHotwordDetection) {
+ Slog.i(TAG, "Hotword validation is already in progress, ignoring.");
+ return;
+ }
+ mPerformingSoftwareHotwordDetection = true;
+
+ startListeningFromMicLocked();
+ }
+ }
+ private void startListeningFromMicLocked() {
// TODO: consider making this a non-anonymous class.
IDspHotwordDetectionCallback internalCallback = new IDspHotwordDetectionCallback.Stub() {
@Override
@@ -286,15 +279,22 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- callback.onDetected(result, null, null);
+ synchronized (mLock) {
+ if (mPerformingSoftwareHotwordDetection) {
+ mSoftwareCallback.onDetected(result, null, null);
+ mPerformingSoftwareHotwordDetection = false;
+ } else {
+ Slog.i(TAG, "Hotword detection has already completed");
+ }
+ }
}
@Override
public void onRejected(HotwordRejectedResult result) throws RemoteException {
if (DEBUG) {
- Slog.d(TAG, "onRejected");
+ Slog.wtf(TAG, "onRejected");
}
- // onRejected isn't allowed here
+ // onRejected isn't allowed here, and we are not expecting it.
}
};
@@ -315,6 +315,7 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "startListeningFromExternalSource");
}
+
handleExternalSourceHotwordDetection(
audioStream,
audioFormat,
@@ -326,16 +327,25 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "stopListening");
}
+ synchronized (mLock) {
+ stopListeningLocked();
+ }
+ }
- mRemoteHotwordDetectionService.run(service -> service.stopDetection());
+ private void stopListeningLocked() {
+ if (!mPerformingSoftwareHotwordDetection) {
+ Slog.i(TAG, "Hotword detection is not running");
+ return;
+ }
+ mPerformingSoftwareHotwordDetection = false;
- synchronized (mLock) {
- if (mCurrentAudioSink != null) {
- Slog.i(TAG, "Closing audio stream to hotword detector: stopping requested");
- bestEffortClose(mCurrentAudioSink);
- }
- mCurrentAudioSink = null;
+ mRemoteHotwordDetectionService.run(IHotwordDetectionService::stopDetection);
+
+ if (mCurrentAudioSink != null) {
+ Slog.i(TAG, "Closing audio stream to hotword detector: stopping requested");
+ bestEffortClose(mCurrentAudioSink);
}
+ mCurrentAudioSink = null;
}
void triggerHardwareRecognitionEventForTestLocked(
@@ -358,7 +368,14 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- externalCallback.onKeyphraseDetected(recognitionEvent, result);
+ synchronized (mLock) {
+ if (mValidatingDspTrigger) {
+ mValidatingDspTrigger = false;
+ externalCallback.onKeyphraseDetected(recognitionEvent, result);
+ } else {
+ Slog.i(TAG, "Ignored hotword detected since trigger has been handled");
+ }
+ }
}
@Override
@@ -366,16 +383,26 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onRejected");
}
- externalCallback.onRejected(result);
+ synchronized (mLock) {
+ if (mValidatingDspTrigger) {
+ mValidatingDspTrigger = false;
+ externalCallback.onRejected(result);
+ } else {
+ Slog.i(TAG, "Ignored hotword rejected since trigger has been handled");
+ }
+ }
}
};
- mRemoteHotwordDetectionService.run(
- service -> service.detectFromDspSource(
- recognitionEvent,
- recognitionEvent.getCaptureFormat(),
- VALIDATION_TIMEOUT_MILLIS,
- internalCallback));
+ synchronized (mLock) {
+ mValidatingDspTrigger = true;
+ mRemoteHotwordDetectionService.run(
+ service -> service.detectFromDspSource(
+ recognitionEvent,
+ recognitionEvent.getCaptureFormat(),
+ VALIDATION_TIMEOUT_MILLIS,
+ internalCallback));
+ }
}
private void detectFromDspSource(SoundTrigger.KeyphraseRecognitionEvent recognitionEvent,
@@ -391,7 +418,14 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onDetected");
}
- externalCallback.onKeyphraseDetected(recognitionEvent, result);
+ synchronized (mLock) {
+ if (!mValidatingDspTrigger) {
+ Slog.i(TAG, "Ignoring #onDetected due to a process restart");
+ return;
+ }
+ mValidatingDspTrigger = false;
+ externalCallback.onKeyphraseDetected(recognitionEvent, result);
+ }
}
@Override
@@ -399,16 +433,88 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "onRejected");
}
- externalCallback.onRejected(result);
+ synchronized (mLock) {
+ if (!mValidatingDspTrigger) {
+ Slog.i(TAG, "Ignoring #onRejected due to a process restart");
+ return;
+ }
+ mValidatingDspTrigger = false;
+ externalCallback.onRejected(result);
+ }
}
};
- mRemoteHotwordDetectionService.run(
- service -> service.detectFromDspSource(
- recognitionEvent,
- recognitionEvent.getCaptureFormat(),
- VALIDATION_TIMEOUT_MILLIS,
- internalCallback));
+ synchronized (mLock) {
+ mValidatingDspTrigger = true;
+ mRemoteHotwordDetectionService.run(
+ service -> service.detectFromDspSource(
+ recognitionEvent,
+ recognitionEvent.getCaptureFormat(),
+ VALIDATION_TIMEOUT_MILLIS,
+ internalCallback));
+ }
+ }
+
+ void forceRestart() {
+ if (DEBUG) {
+ Slog.i(TAG, "Requested to restart the service internally. Performing the restart");
+ }
+ synchronized (mLock) {
+ restartProcessLocked();
+ }
+ }
+
+ private void restartProcessLocked() {
+ if (DEBUG) {
+ Slog.i(TAG, "Restarting hotword detection process");
+ }
+
+ ServiceConnection oldConnection = mRemoteHotwordDetectionService;
+
+ // TODO(volnov): this can be done after connect() has been successful.
+ if (mValidatingDspTrigger) {
+ // We're restarting the process while it's processing a DSP trigger, so report a
+ // rejection. This also allows the Interactor to startReco again
+ try {
+ mCallback.onRejected(new HotwordRejectedResult.Builder().build());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to call #rejected");
+ }
+ mValidatingDspTrigger = false;
+ }
+
+ mUpdateStateAfterStartFinished.set(false);
+ mLastRestartInstant = Instant.now();
+
+ // Recreate connection to reset the cache.
+ mRemoteHotwordDetectionService = mServiceConnectionFactory.create();
+
+ if (DEBUG) {
+ Slog.i(TAG, "Started the new process, issuing #onProcessRestarted");
+ }
+ try {
+ mCallback.onProcessRestarted();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to communicate #onProcessRestarted", e);
+ }
+
+ // Restart listening from microphone if the hotword process has been restarted.
+ if (mPerformingSoftwareHotwordDetection) {
+ Slog.i(TAG, "Process restarted: calling startRecognition() again");
+ startListeningFromMicLocked();
+ }
+
+ if (mCurrentAudioSink != null) {
+ Slog.i(TAG, "Closing external audio stream to hotword detector: process restarted");
+ bestEffortClose(mCurrentAudioSink);
+ mCurrentAudioSink = null;
+ }
+
+ if (DEBUG) {
+ Slog.i(TAG, "#onProcessRestarted called, unbinding from the old process");
+ }
+ oldConnection.ignoreConnectionStatusEvents();
+ oldConnection.unbind();
}
static final class SoundTriggerCallback extends IRecognitionStatusCallback.Stub {
@@ -462,139 +568,13 @@ final class HotwordDetectionConnection {
}
}
- // TODO: figure out if we need to let the client configure some of the parameters.
- private static AudioRecord createAudioRecord(
- @NonNull SoundTrigger.KeyphraseRecognitionEvent recognitionEvent) {
- int sampleRate = recognitionEvent.getCaptureFormat().getSampleRate();
- return new AudioRecord(
- new AudioAttributes.Builder()
- .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
- recognitionEvent.getCaptureFormat(),
- getBufferSizeInBytes(
- sampleRate,
- MAX_STREAMING_SECONDS,
- recognitionEvent.getCaptureFormat().getChannelCount()),
- recognitionEvent.getCaptureSession());
- }
-
- @Nullable
- private AudioRecord createMicAudioRecord(AudioFormat audioFormat) {
- if (DEBUG) {
- Slog.i(TAG, "#createAudioRecord");
- }
- try {
- AudioRecord audioRecord = new AudioRecord(
- new AudioAttributes.Builder()
- .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build(),
- audioFormat,
- getBufferSizeInBytes(
- audioFormat.getSampleRate(),
- MICROPHONE_BUFFER_LENGTH_SECONDS,
- audioFormat.getChannelCount()),
- AudioManager.AUDIO_SESSION_ID_GENERATE);
-
- if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
- Slog.w(TAG, "Failed to initialize AudioRecord");
- audioRecord.release();
- return null;
- }
-
- return audioRecord;
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Failed to create AudioRecord", e);
- return null;
- }
- }
-
- @Nullable
- private AudioRecord createFakeAudioRecord() {
- if (DEBUG) {
- Slog.i(TAG, "#createFakeAudioRecord");
- }
- try {
- AudioRecord audioRecord = new AudioRecord.Builder()
- .setAudioFormat(new AudioFormat.Builder()
- .setSampleRate(32000)
- .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
- .setChannelMask(AudioFormat.CHANNEL_IN_MONO).build())
- .setAudioAttributes(new AudioAttributes.Builder()
- .setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD).build())
- .setBufferSizeInBytes(
- AudioRecord.getMinBufferSize(32000,
- AudioFormat.CHANNEL_IN_MONO,
- AudioFormat.ENCODING_PCM_16BIT) * 2)
- .build();
-
- if (audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
- Slog.w(TAG, "Failed to initialize AudioRecord");
- audioRecord.release();
- return null;
- }
- return audioRecord;
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Failed to create AudioRecord", e);
- }
- return null;
- }
-
- /**
- * Returns the number of bytes required to store {@code bufferLengthSeconds} of audio sampled at
- * {@code sampleRate} Hz, using the format returned by DSP audio capture.
- */
- private static int getBufferSizeInBytes(
- int sampleRate, int bufferLengthSeconds, int intChannelCount) {
- return BYTES_PER_SAMPLE * sampleRate * bufferLengthSeconds * intChannelCount;
- }
-
- private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
- ParcelFileDescriptor[] fileDescriptors;
- try {
- fileDescriptors = ParcelFileDescriptor.createPipe();
- } catch (IOException e) {
- Slog.e(TAG, "Failed to create audio stream pipe", e);
- return null;
- }
-
- return Pair.create(fileDescriptors[0], fileDescriptors[1]);
- }
-
public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mBound="); pw.println(mBound);
- }
-
- private interface AudioReader extends Closeable {
- int read(byte[] dest, int offset, int length) throws IOException;
-
- static AudioReader createFromInputStream(InputStream is) {
- return new AudioReader() {
- @Override
- public int read(byte[] dest, int offset, int length) throws IOException {
- return is.read(dest, offset, length);
- }
-
- @Override
- public void close() throws IOException {
- is.close();
- }
- };
- }
-
- static AudioReader createFromAudioRecord(AudioRecord record) {
- record.startRecording();
-
- return new AudioReader() {
- @Override
- public int read(byte[] dest, int offset, int length) throws IOException {
- return record.read(dest, offset, length);
- }
-
- @Override
- public void close() throws IOException {
- record.stop();
- record.release();
- }
- };
- }
+ pw.print(prefix);
+ pw.print("mBound=" + mRemoteHotwordDetectionService.isBound());
+ pw.print(", mValidatingDspTrigger=" + mValidatingDspTrigger);
+ pw.print(", mPerformingSoftwareHotwordDetection=" + mPerformingSoftwareHotwordDetection);
+ pw.print(", mRestartCount=" + mServiceConnectionFactory.mRestartCount);
+ pw.println(", mLastRestartInstant=" + mLastRestartInstant);
}
private void handleExternalSourceHotwordDetection(
@@ -605,8 +585,7 @@ final class HotwordDetectionConnection {
if (DEBUG) {
Slog.d(TAG, "#handleExternalSourceHotwordDetection");
}
- AudioReader audioSource = AudioReader.createFromInputStream(
- new ParcelFileDescriptor.AutoCloseInputStream(audioStream));
+ InputStream audioSource = new ParcelFileDescriptor.AutoCloseInputStream(audioStream);
Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe();
if (clientPipe == null) {
@@ -621,7 +600,7 @@ final class HotwordDetectionConnection {
}
mAudioCopyExecutor.execute(() -> {
- try (AudioReader source = audioSource;
+ try (InputStream source = audioSource;
OutputStream fos =
new ParcelFileDescriptor.AutoCloseOutputStream(serviceAudioSink)) {
@@ -681,6 +660,150 @@ final class HotwordDetectionConnection {
}));
}
+ private class ServiceConnectionFactory {
+ private final Intent mIntent;
+ private final int mBindingFlags;
+
+ private int mRestartCount = 0;
+
+ ServiceConnectionFactory(@NonNull Intent intent, boolean bindInstantServiceAllowed) {
+ mIntent = intent;
+ mBindingFlags = bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0;
+ }
+
+ ServiceConnection create() {
+ ServiceConnection connection =
+ new ServiceConnection(mContext, mIntent, mBindingFlags, mUser,
+ IHotwordDetectionService.Stub::asInterface, ++mRestartCount);
+ connection.connect();
+
+ updateAudioFlinger(connection);
+ updateContentCaptureManager(connection);
+ return connection;
+ }
+ }
+
+ private class ServiceConnection extends ServiceConnector.Impl<IHotwordDetectionService> {
+ private final Object mLock = new Object();
+
+ private final Intent mIntent;
+ private final int mBindingFlags;
+ private final int mInstanceNumber;
+
+ private boolean mRespectServiceConnectionStatusChanged = true;
+ private boolean mIsBound = false;
+
+ ServiceConnection(@NonNull Context context,
+ @NonNull Intent intent, int bindingFlags, int userId,
+ @Nullable Function<IBinder, IHotwordDetectionService> binderAsInterface,
+ int instanceNumber) {
+ super(context, intent, bindingFlags, userId, binderAsInterface);
+ this.mIntent = intent;
+ this.mBindingFlags = bindingFlags;
+ this.mInstanceNumber = instanceNumber;
+ }
+
+ @Override // from ServiceConnector.Impl
+ protected void onServiceConnectionStatusChanged(IHotwordDetectionService service,
+ boolean connected) {
+ if (DEBUG) {
+ Slog.d(TAG, "onServiceConnectionStatusChanged connected = " + connected);
+ }
+ synchronized (mLock) {
+ if (!mRespectServiceConnectionStatusChanged) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignored onServiceConnectionStatusChanged event");
+ }
+ return;
+ }
+ mIsBound = connected;
+ }
+ }
+
+ @Override
+ protected long getAutoDisconnectTimeoutMs() {
+ return -1;
+ }
+
+ @Override
+ public void binderDied() {
+ super.binderDied();
+ synchronized (mLock) {
+ if (!mRespectServiceConnectionStatusChanged) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignored #binderDied event");
+ }
+ return;
+ }
+
+ Slog.w(TAG, "binderDied");
+ try {
+ mCallback.onError(-1);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to report onError status: " + e);
+ }
+ }
+ }
+
+ @Override
+ protected boolean bindService(
+ @NonNull android.content.ServiceConnection serviceConnection) {
+ try {
+ return mContext.bindIsolatedService(
+ mIntent,
+ Context.BIND_AUTO_CREATE | mBindingFlags,
+ "hotword_detector_" + mInstanceNumber,
+ mExecutor,
+ serviceConnection);
+ } catch (IllegalArgumentException e) {
+ Slog.wtf(TAG, "Can't bind to the hotword detection service!", e);
+ return false;
+ }
+ }
+
+ boolean isBound() {
+ synchronized (mLock) {
+ return mIsBound;
+ }
+ }
+
+ void ignoreConnectionStatusEvents() {
+ synchronized (mLock) {
+ mRespectServiceConnectionStatusChanged = false;
+ }
+ }
+ }
+
+ private static Pair<ParcelFileDescriptor, ParcelFileDescriptor> createPipe() {
+ ParcelFileDescriptor[] fileDescriptors;
+ try {
+ fileDescriptors = ParcelFileDescriptor.createPipe();
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to create audio stream pipe", e);
+ return null;
+ }
+
+ return Pair.create(fileDescriptors[0], fileDescriptors[1]);
+ }
+
+ private static void updateAudioFlinger(ServiceConnection connection) {
+ // TODO: Consider using a proxy that limits the exposed API surface.
+ IBinder audioFlinger = ServiceManager.getService("media.audio_flinger");
+ if (audioFlinger == null) {
+ throw new IllegalStateException("Service media.audio_flinger wasn't found.");
+ }
+ connection.post(service -> service.updateAudioFlinger(audioFlinger));
+ }
+
+ private static void updateContentCaptureManager(ServiceConnection connection) {
+ IBinder b = ServiceManager
+ .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
+ IContentCaptureManager binderService = IContentCaptureManager.Stub.asInterface(b);
+ connection.post(
+ service -> service.updateContentCaptureManager(binderService,
+ new ContentCaptureOptions(null)));
+ }
+
private static void bestEffortClose(Closeable closeable) {
try {
closeable.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index bc812c2ae4a7..162acba8002d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -795,6 +795,10 @@ public class VoiceInteractionManagerService extends SystemService {
Settings.Secure.ASSISTANT, null, userHandle);
}
+ void forceRestartHotwordDetector() {
+ mImpl.forceRestartHotwordDetector();
+ }
+
@Override
public void showSession(Bundle args, int flags) {
synchronized (this) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index ca30bc51e046..89c5a720ee7e 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -562,6 +562,14 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne
&& (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
}
+ void forceRestartHotwordDetector() {
+ if (mHotwordDetectionConnection == null) {
+ Slog.w(TAG, "Failed to force-restart hotword detection: no hotword detection active");
+ return;
+ }
+ mHotwordDetectionConnection.forceRestart();
+ }
+
public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!mValid) {
pw.print(" NOT VALID: ");
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
index 2e3ca0157a3b..cdd8f7b91d9d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -54,6 +54,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return requestHide(pw);
case "disable":
return requestDisable(pw);
+ case "restart-detection":
+ return requestRestartDetection(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -74,6 +76,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
pw.println("");
pw.println(" disable [true|false]");
pw.println(" Temporarily disable (when true) service");
+ pw.println(" restart-detection");
+ pw.println(" Force a restart of a hotword detection service");
pw.println("");
}
}
@@ -143,6 +147,16 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return 0;
}
+ private int requestRestartDetection(PrintWriter pw) {
+ Slog.i(TAG, "requestRestartDetection()");
+ try {
+ mService.forceRestartHotwordDetector();
+ } catch (Exception e) {
+ return handleError(pw, "requestRestartDetection()", e);
+ }
+ return 0;
+ }
+
private static int handleError(PrintWriter pw, String message, Exception e) {
Slog.e(TAG, "error calling " + message, e);
pw.printf("Error calling %s: %s\n", message, e);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1953af4adee5..e000265f0a2c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1018,6 +1018,16 @@ public class TelecomManager {
// this magic number is a bug ID
public static final long ENABLE_GET_CALL_STATE_PERMISSION_PROTECTION = 157233955L;
+ /**
+ * Enable READ_PHONE_NUMBERS or READ_PRIVILEGED_PHONE_STATE protections on
+ * {@link TelecomManager#getPhoneAccount(PhoneAccountHandle)}.
+ * @hide
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
+ // bug ID
+ public static final long ENABLE_GET_PHONE_ACCOUNT_PERMISSION_PROTECTION = 183407956L;
+
private static final String TAG = "TelecomManager";
@@ -1351,6 +1361,9 @@ public class TelecomManager {
* Return the {@link PhoneAccount} for a specified {@link PhoneAccountHandle}. Object includes
* resources which can be used in a user interface.
*
+ * Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_NUMBERS} for applications targeting API
+ * level 31+.
* @param account The {@link PhoneAccountHandle}.
* @return The {@link PhoneAccount} object.
*/
@@ -1358,7 +1371,7 @@ public class TelecomManager {
ITelecomService service = getTelecomService();
if (service != null) {
try {
- return service.getPhoneAccount(account);
+ return service.getPhoneAccount(account, mContext.getPackageName());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccount", e);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 18afde742abb..6f286d9f3006 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -79,7 +79,7 @@ interface ITelecomService {
/**
* @see TelecomManager#getPhoneAccount
*/
- PhoneAccount getPhoneAccount(in PhoneAccountHandle account);
+ PhoneAccount getPhoneAccount(in PhoneAccountHandle account, String callingPackage);
/**
* @see TelecomManager#getAllPhoneAccountsCount
diff --git a/tests/Internal/src/android/app/WallpaperColorsTest.java b/tests/Internal/src/android/app/WallpaperColorsTest.java
index 45d3dade82b6..9ffb236d3f59 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -20,6 +20,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -106,4 +107,26 @@ public class WallpaperColorsTest {
// This would crash:
canvas.drawBitmap(image, 0, 0, new Paint());
}
+
+ /**
+ * Parcelled WallpaperColors object should equal the original.
+ */
+ @Test
+ public void testParcelUnparcel() {
+ Bitmap image = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888);
+ WallpaperColors colors = WallpaperColors.fromBitmap(image);
+ Parcel parcel = Parcel.obtain();
+ colors.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ WallpaperColors reconstructed = new WallpaperColors(parcel);
+ parcel.recycle();
+ Assert.assertEquals("WallpaperColors recreated from Parcel should equal original",
+ colors, reconstructed);
+ Assert.assertEquals("getAllColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getAllColors(), reconstructed.getAllColors());
+ Assert.assertEquals("getMainColors() on WallpaperColors recreated from Parcel should"
+ + "return the same as the original",
+ colors.getMainColors(), reconstructed.getMainColors());
+ }
}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index c679d0487629..c563e06ab528 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -52,6 +52,7 @@ java_test_host {
data: [
":com.android.apex.apkrollback.test_v1",
":com.android.apex.cts.shim.v2_prebuilt",
+ ":StagedInstallTestApexV2_WrongSha",
":TestAppAv1",
],
test_suites: ["general-tests"],
diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
index e633c87d7fbb..6a62304f9af7 100644
--- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java
@@ -179,6 +179,26 @@ public class StagedInstallInternalTest {
assertThat(info.isStagedSessionFailed()).isTrue();
}
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Commit() throws Exception {
+ int sessionId = Install.single(TestApp.Apex1).setStaged().commit();
+ assertSessionReady(sessionId);
+ storeSessionId(sessionId);
+ }
+
+ @Test
+ public void testApexActivationFailureIsCapturedInSession_Verify() throws Exception {
+ int sessionId = retrieveLastSessionId();
+ assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash");
+ }
+
+ private static void assertSessionFailedWithMessage(int sessionId, String msg) {
+ assertSessionState(sessionId, (session) -> {
+ assertThat(session.isStagedSessionFailed()).isTrue();
+ assertThat(session.getStagedSessionErrorMessage()).contains(msg);
+ });
+ }
+
private static void assertSessionReady(int sessionId) {
assertSessionState(sessionId,
(session) -> assertThat(session.isStagedSessionReady()).isTrue());
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index ccd63f94de54..5d7fdd183dec 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -56,6 +56,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Rule
public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this);
private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex";
+ private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex";
private static final String APK_A = "TestAppAv1.apk";
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
@@ -322,6 +323,27 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify");
}
+ @Test
+ public void testApexActivationFailureIsCapturedInSession() throws Exception {
+ // We initiate staging a normal apex update which passes pre-reboot verification.
+ // Then we replace the valid apex waiting in /data/app-staging with something
+ // that cannot be activated and reboot. The apex should fail to activate, which
+ // is what we want for this test.
+ runPhase("testApexActivationFailureIsCapturedInSession_Commit");
+ final String sessionId = getDevice().executeShellCommand(
+ "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim();
+ assertThat(sessionId).isNotEmpty();
+ // Now replace the valid staged apex with something invalid
+ getDevice().enableAdbRoot();
+ getDevice().executeShellCommand("rm /data/app-staging/session_" + sessionId + "/*");
+ final File invalidApexFile = mHostUtils.getTestFile(APEX_WRONG_SHA);
+ getDevice().pushFile(invalidApexFile,
+ "/data/app-staging/session_" + sessionId + "/base.apex");
+ getDevice().reboot();
+
+ runPhase("testApexActivationFailureIsCapturedInSession_Verify");
+ }
+
private List<String> getStagingDirectories() throws DeviceNotAvailableException {
String baseDir = "/data/app-staging";
try {
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 4ce78aa4d8c1..dc338ae0fdc7 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -20,6 +20,8 @@ import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -70,6 +72,14 @@ public class VcnGatewayConnectionConfigTest {
public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
private static int sGatewayConnectionConfigCount = 0;
+ private static VcnGatewayConnectionConfig buildTestConfig(
+ String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) {
+ return buildTestConfigWithExposedCaps(
+ new VcnGatewayConnectionConfig.Builder(
+ gatewayConnectionName, tunnelConnectionParams),
+ EXPOSED_CAPS);
+ }
+
// Public for use in VcnGatewayConnectionTest
public static VcnGatewayConnectionConfig buildTestConfig() {
return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
@@ -83,10 +93,9 @@ public class VcnGatewayConnectionConfigTest {
TUNNEL_CONNECTION_PARAMS);
}
- // Public for use in VcnGatewayConnectionTest
- public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
- final VcnGatewayConnectionConfig.Builder builder =
- newBuilder().setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
+ private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
+ VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
+ builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
for (int caps : exposedCaps) {
builder.addExposedCapability(caps);
@@ -95,6 +104,11 @@ public class VcnGatewayConnectionConfigTest {
return builder.build();
}
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
+ return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
+ }
+
@Test
public void testBuilderRequiresNonNullGatewayConnectionName() {
try {
@@ -193,4 +207,46 @@ public class VcnGatewayConnectionConfigTest {
assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
}
+
+ private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
+ final IkeSessionParams ikeParams =
+ IkeSessionParamsUtilsTest.createBuilderMinimum()
+ .setAuthPsk(ikePsk.getBytes())
+ .build();
+ return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsEquals.connectionName";
+ final String psk = "testTunnelConnectionParamsEquals.psk";
+
+ final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk);
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotSame(tunnelParams, anotherTunnelParams);
+ assertEquals(tunnelParams, anotherTunnelParams);
+ assertEquals(config, anotherConfig);
+ }
+
+ @Test
+ public void testTunnelConnectionParamsNotEquals() throws Exception {
+ final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName";
+
+ final IkeTunnelConnectionParams tunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA");
+ final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
+
+ final IkeTunnelConnectionParams anotherTunnelParams =
+ buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB");
+ final VcnGatewayConnectionConfig anotherConfig =
+ buildTestConfig(connectionName, anotherTunnelParams);
+
+ assertNotEquals(tunnelParams, anotherTunnelParams);
+ assertNotEquals(config, anotherConfig);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index f681ee19ab12..5d2f9d748581 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -242,6 +242,27 @@ public class VcnTest {
verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE);
}
+ @Test
+ public void testSubscriptionSnapshotUpdatesMobileDataState() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
+
+ // Expect mobile data enabled from setUp()
+ assertTrue(mVcn.isMobileDataEnabled());
+
+ final TelephonySubscriptionSnapshot updatedSnapshot =
+ mock(TelephonySubscriptionSnapshot.class);
+ doReturn(TEST_SUB_IDS_IN_GROUP)
+ .when(updatedSnapshot)
+ .getAllSubIdsInGroup(eq(TEST_SUB_GROUP));
+ doReturn(false).when(mTelephonyManager).isDataEnabled();
+
+ mVcn.updateSubscriptionSnapshot(updatedSnapshot);
+ mTestLooper.dispatchAll();
+
+ assertFalse(mVcn.isMobileDataEnabled());
+ }
+
private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
for (final int[] caps : TEST_CAPS) {
startVcnGatewayWithCapabilities(requestListener, caps);